Skip to main content

Reified type parameters

Short answer

reified lets an inline generic function use the caller's real type, such as String, inside the function. It enables code such as value is T and T::class. Without it, the JVM normally forgets what T was.

The problem: an ordinary T is not available at runtime​

Consider a normal generic function:

fun <T> echo(value: T): T = value

The caller knows the type:

echo<String>("Android")

But on the JVM, most generic type information is erased. In simple terms, the runtime function usually does not receive a separate value saying, “T is String.” Therefore, this does not compile:

// Does not compile:
// fun <T> isType(value: Any): Boolean = value is T

The compiler cannot generate a runtime is T check when the runtime does not know what T means.

The solution: inline plus reified​

An inline function can mark a type parameter reified:

inline fun <reified T> isType(value: Any): Boolean = value is T

println(isType<String>("Android")) // true
println(isType<Int>("Android")) // false

For isType<String>("Android"), Kotlin can conceptually place this at the call site:

"Android" is String

For isType<Int>("Android"), it can place:

"Android" is Int

That is why the first result is true and the second is false.

Open in Kotlin Playground
Expected: true, false, and true.

Why inline is required​

At each call site, the compiler knows the actual type:

isType<String>(value)

Because the function is inlined, the compiler can place a real String check into the generated code. Without inlining, the runtime would see only an erased T.

reified is therefore allowed only on an inline function. A non-inline function has one shared runtime body and cannot specialize that body separately at every call site.

Accessing the class​

inline fun <reified T> typeName(): String =
T::class.simpleName ?: "Unknown"

For Java reflection APIs, use T::class.java:

inline fun <reified T : Any> javaClassOf(): Class<T> = T::class.java
Open in Kotlin Playground
Expected: String, Double, and the JVM class name for Kotlin Int.

Filtering by runtime type​

inline fun <reified T> List<*>.valuesOfType(): List<T> =
filterIsInstance<T>()
val numbers = listOf(1, "two", 3L, 4).valuesOfType<Int>()
println(numbers) // [1, 4]

Step by step:

  1. The source list accepts different value types because its element type is broad.
  2. The caller requests valuesOfType<Int>().
  3. filterIsInstance<Int>() checks each value at runtime.
  4. Only 1 and 4 pass the check; the String and Long are removed.
Open in Kotlin Playground
Expected: [1, 4], [two], and [3].

Reified does not preserve every nested generic detail​

inline fun <reified T> check(value: Any) = value is T

A check such as check<List<String>>(value) can confirm that the value is a List, but it cannot reliably prove that every element is a String. The outer List type is visible; its nested element type is still erased.

✕ Do not assume nested elements were validated

val value: Any = listOf(1, 2, 3)
val looksLikeStrings = check<List<String>>(value)

The outer object is a List, so the check can be true even though its elements are integers.

✓ Validate the elements when element type matters

val allStrings = (value as? List<*>)?.all { element -> element is String } == true
Open in Kotlin Playground
Expected: the outer reified check reports true, while explicit element validation reports false.

Alternative: pass type information explicitly​

Without reified types, accept a class or type token:

fun <T : Any> isType(value: Any, type: Class<T>): Boolean =
type.isInstance(value)

isType("Android", String::class.java)

This is useful when the function cannot be inline, when Java callers need a straightforward API, or when a serialization library requires richer type information.

Open in Kotlin Playground
Expected: true, followed by false.

Android examples​

Reified helpers are often used for:

  • Typed navigation or Intent helpers
  • Looking up services by class
  • Dependency containers
  • Serialization wrappers
  • Filtering heterogeneous values

Keep public framework helpers honest: a concise reified API should still validate missing or malformed data and should not hide lifecycle or serialization failures.

Android-only example shape​

inline fun <reified T : Activity> Context.openActivity() {
startActivity(Intent(this, T::class.java))
}

This snippet requires Android's Activity, Context, and Intent, so it cannot run in plain Kotlin Playground. The Kotlin-only pages demonstrate the same T::class.java mechanism without Android dependencies.

Interview-ready answer

JVM type erasure normally prevents an ordinary generic function from checking value is T or using T::class. An inline function with a reified type parameter receives the actual type at each call site, enabling those operations. It still cannot fully recover nested generic element types erased by the JVM.

Quick questions​

Can a non-inline function use a reified type parameter?

No. Reification works because the compiler substitutes the actual type while inlining the function at the call site.

Is reified always better than passing Class&lt;T&gt;?

No. An explicit class or type token can work from Java, avoids forcing an inline API, and may represent richer generic information depending on the library.