Although the exact details of the type system are implementation dependent, let me delve deeper into more than just saying it depends, and you don't care. I will describe how it roughly works in a Microsoft (.NET) implementation according to the CLR book through C # by Jeffrey Richter , and the article See How CLR Creates Run-Time Objects by Hanu Kommalapati et al. ( Original MSDN May 2005 ).
Say you have a class:
class Foo { // Instance fields string myBar = "Foobar"; int myNum; // Static fields static string bar = "Foobar"; static int num; } Foo myFoo = new Foo(); Type typeOfFoo = typeof(Foo);
Where do the specimens live?
Whenever you say new Foo() , space is allocated and initialized for an instance of the object, and the constructor is called. This instance is shown as an instance of Foo in the image below. For example, an instance contains only the fields of the class instance (in this case myBar and myNum ), and for objects allocated on the heap, two additional fields used by the runtime ( Sync block index and Type handle ). A type pointer is a pointer to a Type object that describes the type of the instance, in this case the type is Foo.
When you say new Foo() again, a new space will be allocated that will again contain a space for the instance fields of this type. As you can see, instance fields are associated with object instances.
The runtime places each instance field with a fixed offset from the start of the object data. For example, myBar can live with an offset of +4. The instance field address is simply the address of the object plus the field offset.
Where do static fields live?
Static fields in C # and Java are not associated with any object instance, but with a type. Classes, structures, and enumerations are examples of types. Only once (for each type) is some space allocated for storing values of static fields. It would be advisable to allocate space for static fields in the Type structure, which describes the type, since there is only one Type object for each type. This is the approach used by C # and Java.
A Type 1 object is created when the type is loaded by the runtime. This structure contains all kinds of information necessary for the runtime to highlight new instances, call methods, and cast, among other things. It also contains space for static fields, in this case bar and num .
Runtime puts each static field at some offset from the start of the type data. This is different for each type. For example, bar can live with an offset of +64. The address of a static field is the address of the Type object plus the field offset. The type is statically known.

1 ). In Microsoft.NET, several different structures describe a type, for example, the MethodTable method and EEClass structures.