Don’t Overlook the Basics: Understanding Type in C#

Published: (February 2, 2026 at 02:31 AM EST)
6 min read
Source: Dev.to

Source: Dev.to

Introduction

Understanding types is one of the most important basics in C#. Every type, no matter what, is ultimately connected to a “big boss” type called System.Object. This means that, behind the scenes, all types share some common features.

Example

// This class automatically inherits from System.Object
class Music { }

// This is the same as above, just written out
class Opera : System.Object { }

No matter what you create, it all starts with System.Object. This gives you useful methods like ToString() and GetHashCode() for every object.

Types in C#: The Basics

In C#, types are grouped into two main categories:

  • Value Types
  • Reference Types

There’s also a special group called primitive types, which are the most basic built‑in types.

Let’s break these down!

Primitive Types

Primitive types are the simplest types built into C#. They are easy for the compiler to use and map directly to types in the .NET framework.

Examples: int, double, bool, char, byte, short, long, float, decimal

  • Primitive types are a subset of value types.
  • They have default values (int is 0, bool is false, etc.).
  • They are fast and efficient.
int   count = 5;    // int is a primitive type
bool  isOn = true; // bool is a primitive type

Value Types

Value types hold their actual data. They’re stored in a quick‑access area called the stack. When you assign a value type to another variable, it copies the value.

Examples: All primitive types, struct, enum

  • Value types always have a value, even if you don’t set one.
  • They can’t be null (unless you use a nullable type).
  • Assignment copies the value—not just a reference.

All value types (structs, enums, primitive types) inherit from System.ValueType.

int number = 10;          // Value type, default is 0 if not set
int copy   = number;      // Copies the value (10)

Why Are Value Types Sealed?

  • Immutability of layout: Their memory layout is fixed; inheritance would make size and structure unpredictable.
  • Performance: The sealed nature lets the runtime optimize storage and access.
  • Simplicity: Inheriting value types would complicate assignment, boxing, and unboxing.

The following code will not compile:

struct BasePoint { public int X, Y; }

// Error! Cannot derive from a sealed type
struct DerivedPoint : BasePoint { public int Z; }

You also cannot use a value type as a base for a reference type:

struct BaseStruct { }

// Error! Cannot derive from a value type
class MyClass : BaseStruct { }

How to Create Your Own Value Type

Using struct

A struct is a user‑defined value type. Here’s a simple 2‑D point:

public struct Point
{
    public int X;
    public int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}
Point a = new Point(1, 2);
Point b = a;   // Copies the value (not a reference)
b.X = 10;

// a.X is still 1, b.X is 10

Using enum

All enumerations inherit from the abstract System.Enum type, which itself derives from System.ValueType. An enum is another kind of value type you can create:

public enum DayOfWeek
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
}
  • structs and enums are the only ways to create custom value types.
  • Value types are stored on the stack (or inline in objects) and behave differently from reference types (classes).
  • You cannot inherit from a struct or enum, nor can they inherit from anything except System.ValueType.

Nullable Value Types

Sometimes you want a value type to be able to hold null (e.g., when the value isn’t set yet). In C#, you can do this with a nullable type:

int? score = null; // 'score' can now be null

if (score == null)
{
    Console.WriteLine("No score yet!");
}

Reference Types

Reference types store a reference (address) to their data. The actual data lives on the heap, and the variable simply points to it. When you assign a reference type to another variable, it copies the reference, not the actual data.

Examples: class, string, array, delegate, interface, object

  • Reference types can be null (they may not point to any object).
  • Using a reference type before it’s assigned results in a NullReferenceException.
  • Assignment copies the reference (address), not the data.
string name; // This is null by default

// Using 'name' before assigning a value causes an error
// Console.WriteLine(name.Length); // NullReferenceException!

How Memory Is Allocated: Value vs. Reference Types

One of the most important distinctions in C# is where the data lives:

AspectValue TypesReference Types
LocationStack (or inline within another object)Heap (managed by the garbage collector)
AssignmentCopies the actual dataCopies the reference (pointer)
Default valueZero‑initialized (e.g., 0, false)null
NullabilityNot nullable unless wrapped (int?)Can be null
InheritanceInherit from System.ValueType (sealed)Inherit from System.Object

Understanding these differences helps you write more efficient, predictable, and bug‑free C# code.

Differences Between Value and Reference Types

The main difference between value and reference types is how and where they are stored in memory.

Value Types – Stored on the Stack

Value types are usually stored on the stack—a fast, simple part of memory. When you create a value‑type variable, the data lives right there in the variable.

Value type memory layout

Example

int number = 5;
int age    = 20;

Each variable holds its value directly.

Reference Types – Reference and Object Locations

Reference types store the actual object data on the heap, but the reference (the variable that points to the object) can be stored in several places:

Where the reference is declaredWhere the reference lives
Local variable inside a methodStack
Field of a class/structInside the containing object (usually on the heap)
static fieldSpecial static memory area

No matter where the reference is stored, it always points to the object data on the heap.

Reference type memory layout 1

Reference type memory layout 2

Example

class Pet    { public string Name; }
class Person { public Pet pet; }

void Example()
{
    Person p = new Person(); // 'p' is a local variable (reference stored on the stack)
    p.pet = new Pet();       // 'pet' is a field (reference stored inside the Person object on the heap)
}
  • p (the reference to the Person object) lives on the stack because it is a local variable.
  • The Person object itself lives on the heap.
  • Inside the Person object, the pet field holds a reference that points to another heap‑allocated object (Pet).

What Happens When You Copy?

Value‑Type Copy

int a = 10;
int b = a; // b gets its own copy of the value (10)

Value type copy illustration

Reference‑Type Copy

Person p1 = new Person();
Person p2 = p1; // p2 points to the same object as p1

Reference type copy illustration

Both p1 and p2 refer to the same object in memory. Changing the object through either variable is reflected when accessed through the other.

Summary

  • Primitive types (int, bool, etc.) are built‑in value types.
  • Value types hold the actual data and live on the stack.
  • Reference types hold a reference (address). The reference may be stored on the stack, heap, or in a static area, but the object data always lives on the heap.
  • Assigning a value type copies the data; assigning a reference type copies the address.
  • All types in C# ultimately derive from System.Object.

Extra Tips for Beginners

  • A NullReferenceException means you tried to use a reference type that hasn’t been instantiated.
  • Use nullable value types (int?, double?, …) when you need a value type that can also be null.
  • Passing a value type to a method copies its value; passing a reference type copies the reference.

Understanding these basics will help you write safer and more efficient C# code. Happy coding!

Back to Blog

Related posts

Read more »

Methods and Parameter Usage in C#

Defining and Calling Methods csharp static void Greet { Console.WriteLine'Hello!'; } static void Main { Greet; // method call } text // Output: Hello! Methods...

Operators

What are Operators in Java? Operators are symbols used to perform operations on variables and values. Types of Operators in Java - Arithmetic Operators - Assig...