You don't need to use a uniform field representation, and the representation in the object doesn't need to match the representation on the stack/in registers.
For example Dylan language doesn't have primitives as such. The d2c compiler passes objects around as a two-element struct containing a type tag and a value (in practice values get passed around in a pair of registers). Now, if you have a field with the declaration <object>, and you store a <double> in there, then the field will consist of two words: a type tag and the double itself. However, if the field is declared as a <double>, then the field will be stored as just the double, and the field accessor code will add the (constant) type tag as the field is read.
For example Dylan language doesn't have primitives as such. The d2c compiler passes objects around as a two-element struct containing a type tag and a value (in practice values get passed around in a pair of registers). Now, if you have a field with the declaration <object>, and you store a <double> in there, then the field will consist of two words: a type tag and the double itself. However, if the field is declared as a <double>, then the field will be stored as just the double, and the field accessor code will add the (constant) type tag as the field is read.