C# typeof Keyword: Syntax, Usage, and Runtime Behavior
c# typeof keyword: Learn how the C# typeof keyword works, how it differs from GetType(), and when to use it for type checks, generics, and reflection.
c# typeof keyword requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
The typeof operator in C# returns a System.Type instance for a type that is known at compile time. For example, typeof(string) yields the Type object representing System.String. Unlike GetType(), which is called on an object instance and returns the runtime type, typeof works purely on the type name or type parameter. This distinction matters whenever you need to reason about types without an instance.
The typeof Operator Returns a Compile-Time Type Reference
typeof is a C# operator, not a method. It takes a type name or a type parameter as its operand and produces a Type object. The operand must be a type that the compiler can resolve at compile time—a concrete class, an interface, a struct, an enum, a generic type parameter, or a constructed generic type.
Type stringType = typeof(string); Type listType = typeof(List<int>); Type dictType = typeof(Dictionary<string, int>);
Because the type is known at compile time, the compiler embeds a reference to the metadata token for that type directly into the assembly. No runtime lookup is required to obtain the Type object. This is why typeof is often described as a compile-time constant expression, even though the resulting Type object is a runtime object.
typeof vs GetType(): What Each One Resolves
GetType() is a method defined on System.Object. It is called on an instance and returns the exact runtime type of that instance. The crucial difference is that GetType() requires an object and reflects the actual type created at runtime, which may be a derived type.
object obj = "hello"; Type runtimeType = obj.GetType(); // System.String Type compileTimeType = typeof(object); // System.Object
In this example, runtimeType is System.String because the runtime object is a string, while compileTimeType is System.Object because the declared type of obj is object. typeof cannot see the runtime type; it only knows the type that appears in the source code.
Choose typeof when you need the type of a known type name or type parameter. Choose GetType() when you have an instance and need its actual runtime type, especially when polymorphism is involved.
Using typeof with Generic Type Parameters
Inside a generic method or class, typeof(T) returns the Type object for the type argument supplied at runtime. This is a common pattern when you need to perform type-specific logic without knowing the concrete type at compile time.
public static string GetTypeName<T>() { return typeof(T).Name; } Console.WriteLine(GetTypeName<int>()); // Int32 Console.WriteLine(GetTypeName<DateTime>()); // DateTime
Because T is a type parameter, the compiler resolves typeof(T) to the actual type argument when the generic method is instantiated. This works for any type, including nullable value types and reference types.
One limitation is that typeof cannot be used with an unbound generic type parameter in certain contexts. For example, you cannot write typeof(T) inside a generic class if T is not constrained to be a type that can be represented as a Type object—though in practice, typeof(T) is always valid for a type parameter. The restriction appears when you try to use typeof on an open generic type definition, such as typeof(List<>). That is allowed, but it returns the generic type definition without type arguments.
Practical Applications of typeof in Real Code
The primary use of typeof is to obtain a Type object for reflection or type-based logic. Common scenarios include:
- Checking type compatibility:
typeof(IEnumerable).IsAssignableFrom(typeof(List<int>))returnstruebecauseList<int>implementsIEnumerable. - Creating instances via reflection:
Activator.CreateInstance(typeof(MyClass))requires aTypeobject. - Applying attributes:
typeof(MyClass).GetCustomAttributes(typeof(SerializableAttribute), false)inspects metadata. - Generic type constraints:
typeof(T)inside a generic method can be used to verify that a type argument satisfies a runtime condition.
public static bool ImplementsDisposable<T>() { return typeof(IDisposable).IsAssignableFrom(typeof(T)); }
This pattern is common in dependency injection containers, serializers, and ORM mappers where type metadata drives behavior.
Performance Characteristics of typeof
typeof is a compile-time constant in the sense that the compiler emits a metadata token reference. The actual Type object is resolved by the runtime when the code executes, but the lookup is extremely fast because it uses the metadata token directly. There is no dynamic type resolution, no virtual call, and no allocation beyond the existing Type object.
In contrast, GetType() is a virtual method call that walks the object's type information at runtime. It is still fast, but it involves a method dispatch and may be slightly slower than typeof in hot paths. The difference is negligible in most applications, but if you are writing a tight loop that repeatedly needs the same type, storing the Type object from typeof in a static field avoids repeated calls.
private static readonly Type StringType = typeof(string);
This pattern is common in libraries that cache type metadata for performance-sensitive operations.
Common Pitfalls When Using typeof
One frequent mistake is confusing typeof with GetType() when the runtime type matters. For example, using typeof(obj) is a syntax error because obj is a variable, not a type name. You must use obj.GetType() to get the runtime type of a variable.
Another pitfall involves nullable value types. typeof(int?) returns the Type for Nullable<int>, not for int. If you need to check whether a type is a nullable value type, you must inspect Nullable.GetUnderlyingType(typeof(int?)).
Type nullableType = typeof(int?); Console.WriteLine(nullableType == typeof(int)); // False Console.WriteLine(Nullable.GetUnderlyingType(nullableType) == typeof(int)); // True
Also be careful when using typeof with generic type parameters that might be nullable reference types. The Type object does not encode nullable reference annotations; typeof(string) is the same whether the variable is declared as string or string?. Nullable reference types are a compile-time feature and do not affect the runtime Type object.
Finally, typeof cannot be used on a type that is not known at compile time. If you only have a string containing the type name, you must use Type.GetType(string) or Assembly.GetType(string) instead. This is a common requirement in plugin systems and configuration-driven code.
string typeName = "System.String"; Type t = Type.GetType(typeName); // Requires assembly-qualified name in some cases
Understanding these boundaries helps you choose the correct API and avoid subtle bugs in type-based logic.