skip to content

What do the top-level `enumValues<T>()`, `enumValueOf<T>()`, and `enumEntries<T>()` functions do, and why must `T` be `reified`?

level: middleimportance: should knowfreq 45%

answer

  1. Generic enum access needs reified (erasure otherwise)
  2. enumValues -> Array, enumValueOf -> one by name, enumEntries -> cached List
  3. reified works because the function is inline
  4. Bound is T : Enum<T>
  5. enumValueOf throws IllegalArgumentException if missing

basics

~20 s

They let generic code get an enum's constants without naming the specific enum. enumValues gives all constants, enumValueOf finds one by name, enumEntries gives the cached list. They need reified so the real type is known at runtime.

solid answer

~30 s

Inside a generic function you can't write `T.entries` or `T.values()` because the concrete enum type is erased. Kotlin provides three `inline` helpers with a `reified T : Enum<T>` type parameter: `enumValues<T>()` returns `Array<T>` of all constants, `enumValueOf<T>(name)` resolves one constant by name (throws `IllegalArgumentException` if missing), and `enumEntries<T>()` (Kotlin 1.9+) returns the cached immutable `EnumEntries<T>` like `.entries`. `reified` is required so the compiler can substitute the actual type at each call site during inlining — that's what makes the otherwise-erased `T` available at runtime to enumerate its constants. Prefer `enumEntries<T>()` over `enumValues<T>()` for the same allocation reason as `entries` vs `values()`.

code

kotlin · 6 lines
kotlin
inline fun <reified T : Enum<T>> parseOrNull(text: String): T? =
    runCatching { enumValueOf<T>(text) }.getOrNull()

enum class Mode { READ, WRITE }
val m: Mode? = parseOrNull<Mode>("READ")   // Mode.READ
val n: Mode? = parseOrNull<Mode>("NOPE")   // null

go deeper

for a junior

Knows these helpers exist for getting enum constants generically, even if hazy on reified.

for a middle

Explains erasure, why reified/inline is needed, and the difference between the three helpers including the throw on enumValueOf.

for a senior

Adds the enumEntries allocation advantage, the T : Enum<T> bound, and the compile-time-fixed limitation vs reflection.

for a principal

Discusses API ergonomics, when to fall back to reflection for runtime types, and library design using reified enum helpers.

## The problem: type erasure On the JVM, generic type arguments are **erased** at runtime — a function `fun <T> f()` doesn't know what `T` actually is. So you **cannot** write `T.values()` or `T.entries` directly; there's no concrete enum to ask. ## `reified` + `inline` to the rescue A function marked `inline` has its body copied into each call site. If its type parameter is `reified`, the compiler substitutes the **actual** type argument into that copied body. So `T` becomes a real, known type at every call site, and you *can* enumerate its constants. ```kotlin inline fun <reified T : Enum<T>> printAll() { for (c in enumValues<T>()) println(c.name) // T is real here } printAll<Color>() // compiler inlines with T = Color ``` ## The three helpers - **`enumValues<T>(): Array<T>`** — all constants as an array (array semantics → allocates per call, like `values()`). - **`enumValueOf<T>(name: String): T`** — looks up a constant by exact name; throws `IllegalArgumentException` if no match (mirrors `MyEnum.valueOf`). - **`enumEntries<T>(): EnumEntries<T>`** (stable Kotlin 1.9) — the cached, immutable `List<T>`, the generic analogue of `.entries`. Prefer it for allocation-free iteration. ```kotlin inline fun <reified T : Enum<T>> fromNameOrNull(name: String): T? = enumEntries<T>().firstOrNull { it.name == name } inline fun <reified T : Enum<T>> require(name: String): T = enumValueOf<T>(name) // throws if absent ``` ## Constraints & notes - The bound is `T : Enum<T>` — these only work for enum types. - Because the functions are `inline`, the concrete type is fixed at compile time per call site; you can't pass a `Class<*>`/`KClass` chosen at runtime to them (use reflection for that). - `enumValueOf` is name-sensitive and case-sensitive; handle the exception or pre-validate. ## Why prefer `enumEntries` Same as `entries`: it returns the cached immutable list (zero per-call allocation), whereas `enumValues` clones an array each call.

  • Could you implement `enumValues<T>()` for a `T` decided at runtime via a variable?
    Not with the reified inline form — the type is fixed at compile time per call site. For runtime-chosen types you'd use reflection (`KClass.java.enumConstants`).
  • Which generic helper should you prefer and why?
    `enumEntries<T>()` — it returns the cached immutable list with no per-call allocation, unlike `enumValues<T>()`.

saying these in an interview costs you the question

  • Saying you can call `enumValues<T>()` without `reified`.
  • Thinking `reified` works on non-`inline` functions.
  • Claiming `enumValueOf` returns null on a miss (it throws).
  • Believing these work for arbitrary classes, not just `Enum<T>`.
  • Not knowing `enumEntries` is the allocation-free choice.

context