Skip to main content

How to Resolve Error "CS0081: Type parameter declaration must be an identifier not a type" in C#

The Compiler Error CS0081 is a syntax error related to Generic Definitions. The message reads: "Type parameter declaration must be an identifier not a type".

This error occurs when you confuse defining a generic with using a generic. When you define a generic class or method, you must provide a placeholder name (an identifier like T, U, or TValue). You cannot use a concrete type (like int, string) or a fully qualified class name (like System.DateTime) inside the definition's angle brackets.

This guide explains the difference between declaring generics and instantiating them.

Understanding Generic Declarations

Generics allow you to write code that works with any data type. To do this, you define a Type Parameter (a variable for types).

  • Declaration (Definition): Requires a name for the placeholder.
    • public class Box<T> { ... } (Correct: T is an identifier).
  • Instantiation (Usage): Requires a concrete type.
    • var b = new Box<int>(); (Correct: int is the type).

CS0081 happens when you try to put the "Usage" syntax into the "Declaration" line.

Scenario 1: Using Keywords in Definitions

A common mistake is trying to define a generic method but trying to force it to use a specific type like int or string inside the angle brackets.

Example of error

You might try to write a method that looks generic but uses the int keyword. The compiler rejects this because int is a reserved C# keyword, not a valid identifier for a type parameter.

public class DataProcessor
{
// ⛔️ Error CS0081: Type parameter declaration must be an identifier not a type
// You cannot name your generic placeholder 'int'.
public void ProcessData<int>(int value)
{
// ...
}
}

Solution: Use a Placeholder or Remove Generics

If you want the method to work with any type, rename int to T. If you want it to work only with integers, remove the angle brackets entirely.

Option A: Make it Generic (Works for any type)

public class DataProcessor
{
// ✅ Correct: 'T' is a valid identifier.
public void ProcessData<T>(T value)
{
System.Console.WriteLine(value);
}
}

Option B: Make it Specific (Works only for int)

public class DataProcessor
{
// ✅ Correct: No angle brackets needed for specific types.
public void ProcessData(int value)
{
System.Console.WriteLine(value);
}
}

Scenario 2: Using Fully Qualified Names

Sometimes developers try to be explicit by putting a full class name (including namespace) inside the definition brackets. The compiler sees the dot . and realizes this is a Type reference, not a valid identifier name.

Example of error

namespace MyProject
{
public class Customer { }

// ⛔️ Error CS0081: Type parameter declaration must be an identifier not a type
// 'MyProject.Customer' is a specific existing type, not a placeholder name.
public class Wrapper<MyProject.Customer>
{
// ...
}
}

Solution: Use a Constraint

If your goal was to create a generic class that only accepts Customer objects, you must use a generic constraint (where), not hardcode the type in the brackets.

namespace MyProject
{
public class Customer { }

// ✅ Correct:
// 1. Define the placeholder 'T'.
// 2. Constrain 'T' to be 'Customer' or a subclass of it.
public class Wrapper<T> where T : Customer
{
public void Process(T customer) { }
}
}
note

If you don't need it to be generic at all (i.e., it only wraps Customer and nothing else), just remove the <...> and write a standard class: public class CustomerWrapper { ... }

Conclusion

CS0081 is a syntax error that means you put a specific Type where a Name was expected.

  1. Check the Brackets: Look at <...>.
  2. Check the Content: Is it a keyword like int? Is it a class name like System.String?
  3. The Fix:
    • Change it to T (or TItem, TKey) if you want it to be generic.
    • Remove the <...> entirely if you want it to be a specific method for that type.