Reified type parameters
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 Playgroundtrue, 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
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:
- The source list accepts different value types because its element type is broad.
- The caller requests
valuesOfType<Int>(). filterIsInstance<Int>()checks each value at runtime.- Only
1and4pass the check; theStringandLongare removed.
[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
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 Playgroundtrue, 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.
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<T>?
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.