What is the difference between 'E', 'T', and '?' for Java generics?
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Introduction
In Java generics, E, T, and ? serve fundamentally different roles. E and T are type parameter names, which are naming conventions that act as placeholders for concrete types specified by the caller. The ? wildcard represents an unknown type and is used exclusively in type arguments, not in declarations. Understanding when to use each one is essential for writing flexible, type-safe Java code.
The short version: E and T are names you give to type parameters (by convention), while ? is a language-level construct that means "some type I do not know or care about."
Type Parameters: E, T, K, V, and Others
Type parameters are placeholders declared in angle brackets on a class, interface, or method. When someone uses the class, they supply a concrete type that replaces the placeholder throughout.
When you write Box<String>, every T in the class body becomes String. The compiler enforces type safety at every usage site.
The letters themselves are just conventions, not language rules. You could write Box<Foo> and it would compile. But the Java community follows well-established naming conventions that communicate intent.
| Parameter | Convention | Typical Usage | Example |
T | Type | General-purpose container or method | Box<T>, Comparator<T> |
E | Element | Collections and iterables | List<E>, Set<E>, Queue<E> |
K | Key | Map keys | Map<K, V> |
V | Value | Map values | Map<K, V> |
N | Number | Numeric types | Matrix<N extends Number> |
R | Result/Return | Return types in functional interfaces | Function<T, R> |
S, U | Second, third types | When multiple type parameters are needed | BiFunction<T, U, R> |
These conventions matter because they make generic code self-documenting. When you see E in a method signature, you immediately know it represents an element of a collection.
E for Element: Collection Types
The Java Collections Framework uses E to represent the element type.
The List<E> interface declares E as its type parameter. When you write List<String>, every E in the interface (in add(E e), get(int index) returning E, etc.) is bound to String.
If you write your own collection class, use E to follow the convention.
T for Type: General Containers and Methods
T is the go-to parameter for general-purpose generics that are not specifically collections.
For generic methods, declare the type parameter before the return type.
The <T> before the return type tells the compiler this is a generic method. The caller does not need to specify T explicitly because the compiler infers it from the argument.
The Wildcard ?: An Unknown Type
The wildcard ? is not a type parameter name. It is a language construct that means "some type, but I do not know which one." You use it in type arguments, never in type parameter declarations.
Unbounded Wildcard: <?>
Use <?> when the method works with any type and does not need to know what that type is.
This method accepts List<String>, List<Integer>, List<Employee>, or any other List. Inside the method, you can only read elements as Object because the actual type is unknown.
Upper-Bounded Wildcard: <? extends Type>
Use extends when you need to read from the structure and require a minimum type guarantee.
This accepts List<Integer>, List<Double>, List<BigDecimal>, or any List of a Number subtype. You can read elements as Number, but you cannot add to the list (because the compiler does not know the specific subtype).
Lower-Bounded Wildcard: <? super Type>
Use super when you need to write into the structure.
This accepts List<Integer>, List<Number>, or List<Object>. You can safely add Integer values because any of those list types can hold an Integer. However, reading from the list only guarantees Object.
The PECS Principle
Joshua Bloch's mnemonic from Effective Java captures the rule concisely.
Producer Extends, Consumer Super (PECS)
- If the generic structure produces values for your code to read, use
? extends T. - If the generic structure consumes values that your code writes, use
? super T. - If the structure both produces and consumes, use a concrete type parameter like
T.
Key Differences at a Glance
| Aspect | E / T (Type Parameters) | ? (Wildcard) |
| Role | Named placeholder for a concrete type | Represents an unknown type |
| Where declared | Class, interface, or method declaration | Type argument at a usage site |
| Can you reference it? | Yes, use the name throughout the scope | No, cannot be referenced by name |
| Can you add to a collection? | Yes, List<T> allows add(T) | Only with ? super T |
| Multiple bounds | <T extends Comparable<T> & Serializable> | <? extends Number> (single bound) |
| Convention matters? | Yes, E/T/K/V convey intent | N/A, ? is syntax, not a name |
When to Use Which
Use a type parameter (T, E) when you need to:
- Refer to the same type in multiple places within a signature
- Return the same type that was passed in
- Declare a class or interface that is generic
Use a wildcard (?) when you:
- Do not need to reference the type by name
- Want to accept multiple generic instantiations of the same class
- Are writing a method that only reads from a structure
Common Pitfalls
Thinking E and T have language-level meaning. They are conventions. The compiler treats Box<T> and Box<X> identically. The conventions exist purely for human readability.
Using List<Object> when you mean List<?>. A List<Object> can hold any object, but a method accepting List<Object> will not accept List<String> because generics are invariant. List<?> accepts any List regardless of its element type.
Adding elements to a List<? extends T>. The compiler blocks this because it cannot verify that the element you are adding matches the unknown subtype. Use ? super T for writing.
Confusing <T> method declaration with <?> usage. <T> in a method signature declares a new type variable. <?> in a parameter type is an argument that says "I accept any type here."
Overcomplicating simple signatures with wildcards. If a method takes a List and returns an element from it, a simple <T> parameter is clearer than a wildcard. Only introduce wildcards when the added flexibility is genuinely needed.
Summary
E,T,K,Vare naming conventions for type parameters. They are placeholders that get replaced by concrete types.Econventionally means Element (collections),Tmeans Type (general purpose),K/Vmean Key/Value (maps).?is the wildcard, representing an unknown type. It appears only in type arguments, not declarations.- Use
? extends Twhen reading (producer),? super Twhen writing (consumer), following the PECS principle. - Prefer type parameters when you need to reference the type by name across a signature. Prefer wildcards when the type is irrelevant to the method's logic.
Related reading
- What is the difference between Factory and Strategy patterns?
- What is the difference between @Inject and @Autowired in Spring Framework? Which one to use under what condition?
- What is the difference between List of T and Collectionof T?
- What is the difference between public, private, and protected inheritance?
- What is the difference between Enum.name and Enum.toString?
- What is the difference between ExecutorService.submit and ExecutorService.execute in this code in Java?
- What is the Execute Around idiom?
- What is the generic version of a Hashtable?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.