The Common Type System (CTS) distinguishes between two categories of types: value types and reference types. Every type belongs to exactly one of the categories and every type is derived directly or indirectly from the overall base-type System.Object.
The CTS and the .NET Framework class library both contain pre-defined value types and reference types. This set of types can be extended by user-defined value types and reference types.
A type is a value type, if and only if it is derived from either System.ValueType or System.Enum. Value types are sealed, i.e., they cannot serve as base types for other types.
All other types are reference types. Reference types can be distinguished into self-describing, interfaces and pointer types. Self-describing types are further split into arrays and class types. The class types are user-defined classes and delegates.
The fundamental difference between the value types and reference types lies as to where instances of these types can live and induced by that, what are their semantics with variable assignment, or their use as parameters in method calls.
Instances of reference types always live in the heap. Basically the heap, consists of instances of reference types and free areas. A variable that is of reference type, technically just contains the memory address to place in the heap, i.e. two variables may point to the same object, and if the object is changed via access of the first variable, the change is visible via the second variable.
Variable assignment copies the memory address into the variable, method calls copy the memory address onto the stack.
Instances of value types either live on the stack, or as part of an enclosing type, or in boxed form in the heap. If a variable is of the same type, then variable assignment copies the value into the variable. Also if a method has a parameter of the same type, then the value is copied onto the stack.
If the variable is of reference type (e.g. System.Object), then a hull is created in the heap and the value is copied into this hull, the memory address to this hull is then assigned to the variable. This process is called boxing and a similar process also takes place, in case the respective function parameter is of the reference type.
Boxing an instance of a value type creates a new hull (and copy) for each boxing operation.
.NET Framework Data Model