skip to content

How does typeOf<T>() work, and why is a reified type parameter usually involved?

level: middleimportance: must knowfreq 50%

answer

  1. typeOf<T>() -> KType, compiler intrinsic
  2. reified T requires inline fun
  3. Captures generics; ::class does not
  4. Basic typeOf needs only stdlib, not full kotlin-reflect
  5. Powers serializer<T>() patterns

basics

~20 s

typeOf<T>() returns the KType for whatever type you put in the angle brackets. To pass a generic type variable T into it from your own function, T must be reified, which only works in an inline function.

solid answer

~40 s

typeOf<T>() is a kotlin-reflect-light intrinsic (declared in kotlin.reflect) that returns the full KType for the type argument T, including its generic arguments and nullability — e.g. typeOf<Map<String, List<Int>>>(). With a concrete type you can call it directly. To capture a caller's generic parameter, you write an inline fun with a reified T, because reified makes the actual type available at the call site where the compiler substitutes it. Without reified, T is erased and typeOf<T>() won't compile. Importantly, typeOf is special: it does NOT require the heavy kotlin-reflect artifact for the basic KType, only kotlin-stdlib, although fully resolving some members may. This pattern underpins kotlinx.serialization's reified serializer<T>() and similar APIs. Compared to ::class (a KClass), typeOf<T>() preserves generics that ::class throws away.

code

kotlin · 13 lines
kotlin
import kotlin.reflect.KType
import kotlin.reflect.typeOf

// reified forwards the concrete type into typeOf at the call site
inline fun <reified T> describe(): String {
    val t: KType = typeOf<T>()
    return "classifier=${t.classifier}, nullable=${t.isMarkedNullable}, args=${t.arguments}"
}

fun main() {
    println(describe<List<String>?>())
    // classifier=class kotlin.collections.List, nullable=true, args=[kotlin.String]
}

go deeper

for a junior

Knows typeOf<T>() returns a KType for a concrete type.

for a middle

Explains the reified + inline requirement and that typeOf preserves generics unlike ::class.

for a senior

Notes typeOf is a compiler intrinsic working around erasure and that basic use avoids the heavy kotlin-reflect artifact.

for a principal

Designs generic library APIs (e.g. serializer<T>()) on top of reified typeOf and reasons about the dependency/cost trade-offs.

## What typeOf does `typeOf<T>()` (function in `kotlin.reflect`) returns a `KType` describing the type argument `T` exactly as written, complete with generic arguments and nullability. It is a *compiler intrinsic*: the compiler synthesizes the `KType` at the call site, so it works even though the JVM erases generics. ```kotlin import kotlin.reflect.typeOf val kt = typeOf<Map<String, List<Int>?>>() println(kt) // kotlin.collections.Map<kotlin.String, kotlin.collections.List<kotlin.Int>?> ``` ## Why reified shows up If you try to forward a generic parameter from your own function, the parameter is normally **erased** — the function body has no idea what `T` was. `reified` solves this, but `reified` is only legal on an **inline** function. Inlining copies the body to the call site, where the concrete type is known, so the compiler can substitute the real type into `typeOf`. ```kotlin import kotlin.reflect.KType import kotlin.reflect.typeOf inline fun <reified T> kindOf(): KType = typeOf<T>() val a = kindOf<List<String>>() // List<String> val b = kindOf<Int?>() // Int? ``` Without `reified` (or on a non-inline function) `typeOf<T>()` fails to compile with an error that `T` is not a reified type parameter. ## Dependency cost A key, often-missed detail: `typeOf<T>()` for obtaining the `KType` works with only **kotlin-stdlib** — it does **not** force you to pull in the full `org.jetbrains.kotlin:kotlin-reflect` jar. Deeper reflective operations (enumerating members, etc.) may still need `kotlin-reflect`, but the type representation itself is lightweight. ## Relationship to ::class `x::class` and `T::class` (reified) yield a `KClass`, which loses generics. `typeOf<T>()` yields a `KType`, which keeps them. Use `typeOf` whenever the generic shape matters (serialization, type-safe deserialization, generic DI containers). ## A common bridge `typeOf<T>().classifier as? KClass<*>` lets you recover the bare class from a KType when you only need the classifier.

  • Why can't a non-inline function call typeOf<T>() on its own T?
    Because non-inline T is erased; reified (only allowed with inline) is what makes the concrete type available to substitute into typeOf.
  • Does using typeOf force the kotlin-reflect dependency?
    No — obtaining a KType via typeOf works with only kotlin-stdlib. Heavier member resolution may need kotlin-reflect.

saying these in an interview costs you the question

  • Saying reified works on regular (non-inline) functions
  • Claiming typeOf loses generic arguments
  • Thinking typeOf is the same as ::class
  • Asserting typeOf always pulls in the full kotlin-reflect jar

context