skip to content

Why is java.lang.Enum declared as Enum<E extends Enum<E>>?

level: seniorimportance: should knowfreq 30%

answer

  1. enum X compiles to class X extends Enum<X>
  2. Enum implements Comparable<E> → same-enum compareTo only
  3. getDeclaringClass returns Class<E> (precise)
  4. Backs type-safe EnumSet/EnumMap
  5. Canonical library use of a recursive bound

basics

~20 s

So each enum is treated as comparable only to its own kind. The recursive bound lets Enum implement Comparable<E> and lets getDeclaringClass return the exact enum type, preventing you from comparing values of two different enums.

solid answer

~40 s

Enum uses a recursive bound, Enum<E extends Enum<E>>, so that the abstract supertype can express type-safe, self-referential operations specialized to each concrete enum. Concretely, Enum implements Comparable<E>, so compareTo only accepts a value of the *same* enum — you can compare two Days but the compiler stops you comparing a Day to a Month. The bound also lets methods like getDeclaringClass() return Class<E> (the precise enum type) and underpins type-safe EnumSet/EnumMap which are keyed by E. Each enum the compiler generates, e.g. enum Day, becomes class Day extends Enum<Day>, satisfying the bound by passing itself. This is the language library's canonical real-world use of a recursive generic bound — it gives you ordinal-based ordering that's safe per enum type without any per-enum boilerplate.

code

java · 8 lines
java
// Conceptual: what the compiler generates
enum Day { MON, TUE }
// becomes ~ final class Day extends Enum<Day> { ... }

Day.MON.compareTo(Day.TUE);       // OK, compares ordinals
// Day.MON.compareTo(Month.JAN);  // compile error: Month is not a Day

Class<Day> c = Day.MON.getDeclaringClass(); // precise type, thanks to E

go deeper

for a junior

Knows enums are comparable and you can't compare two different enum types, without needing the generic detail.

for a middle

Connects the no-cross-enum-comparison behavior to Enum implementing Comparable<E>.

for a senior

States the full Enum<E extends Enum<E>> declaration and lists the benefits: same-type compareTo, precise Class<E>, EnumSet/EnumMap safety.

for a principal

Uses Enum as the exemplar when justifying a recursive bound in API design, and can contrast it with hand-rolled self-typed hierarchies and their weaker compiler guarantees.

## What an enum compiles to When you write `enum Day { MON, TUE }`, the compiler turns it into a class roughly like `final class Day extends java.lang.Enum<Day>` with `MON` and `TUE` as static constants. So every enum is a subclass of the library class `Enum`, and it passes *itself* as the type argument — exactly the CRGP shape. ## The declaration `java.lang.Enum` is declared: ```java public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable ``` The recursive bound `<E extends Enum<E>>` means "E is an enum type parameterized by itself." Why does the library need this? ## Reason 1: type-safe ordering via Comparable<E> `Enum implements Comparable<E>`. Because `E` is the self type, `compareTo` has signature `int compareTo(E o)` — it accepts only the *same* enum type. The implementation just compares `ordinal()` (declaration position). The payoff: ```java Day.MON.compareTo(Day.TUE); // OK // Day.MON.compareTo(Month.JAN); // compile error: different enum types ``` Without the recursive bound, `Enum` could only be `Comparable<Enum>` or raw, and the compiler would let you compare values from two unrelated enums — a meaningless, bug-prone operation. ## Reason 2: precise return types `getDeclaringClass()` returns `Class<E>`, the *exact* enum class, not `Class<? extends Enum>`. Generic code that takes an enum can therefore recover the specific type. `Enum.valueOf(Class<T> enumType, String name)` likewise uses the bound to tie the class token to the returned constant type. ## Reason 3: type-safe enum collections `EnumSet<E extends Enum<E>>` and `EnumMap<K extends Enum<K>, V>` reuse the same bound. An `EnumSet<Day>` can only hold `Day` constants; the bound is what lets these collections be both extremely efficient (bit-vector / array backed by `ordinal()`) and statically type-safe. ## Why not just `Enum<E>` without the bound? A plain `Enum<E>` would let you write `class Weird extends Enum<String>` (well, ignoring that enums are compiler-generated) and would not constrain `E` to actually be an enum or to be the self type, breaking the `Comparable<E>` and ordinal contracts. The self-bound expresses the real invariant: "the type parameter is this very enum." ## Key takeaways - Enum is the textbook *library* example of a recursive generic bound / CRGP. - The bound delivers: same-type-only `compareTo`, precise `Class<E>`/`valueOf` typing, and type-safe `EnumSet`/`EnumMap`. - You never write the bound yourself for enums — the compiler does `enum X` → `class X extends Enum<X>` automatically — but understanding it explains why cross-enum comparison won't compile.

  • What stops you from comparing Day.MON.compareTo(Month.JAN)?
    Enum implements Comparable<E> where E is the self enum type, so Day's compareTo accepts only a Day. Passing a Month is a compile error — the recursive bound enforces same-type comparison.
  • Can you extend java.lang.Enum directly in your own class?
    No. The compiler forbids extending Enum explicitly; you must use the enum keyword, which generates the extends Enum<Self> for you. This keeps the self-bound invariant intact.

saying these in an interview costs you the question

  • Saying the bound is just decorative — it actively blocks cross-enum compareTo
  • Thinking you write Enum<X> by hand — the compiler generates it
  • Believing enums can be compared across types because they all extend Enum

context