reified is a keyword in Kotlin that allows access to the generic parameter type inside inline functions at runtime. In regular generics, type erasure applies — type information is erased at compile time, but reified preserves it. According to Kotlin Documentation, 2025, reified only works inside inline functions because the compiler substitutes the real type at the inlining stage.
Key Takeaways
reified is a modifier for a generic parameter of an inline function that makes the type real (reify — “to make real”) at runtime. Without reified, the type T inside a generic function is inaccessible — the compiler applies type erasure, removing all type information. reified forces the compiler to substitute the concrete type at the call site, making it accessible via T::class and the is operator.
According to the Kotlin Survey by Kodee (2024), reified type parameters rank among the top ten most demanded Kotlin features — they are used by 52% of surveyed developers, primarily for writing generic factories, DI containers, and serializers. reified is especially popular in combination with Gson, Moshi, and Kotlinx Serialization.
Technically, the mechanism is simple: when calling an inline function with a reified parameter, the compiler knows the concrete type argument (Int, String, User) and substitutes it for T. In bytecode, the reified parameter becomes a regular Class<T> passed as a hidden argument.
Use reified for writing generic functions where the type is needed at runtime — instance creation, type checks, obtaining Class<T> for reflection or serialization.
Type erasure is a mechanism in Java and Kotlin where generic parameter information is erased during compilation. In bytecode, List<String> and List<Int> become just List. This was done for backward compatibility with Java 1.4, which did not have generics, but it creates limitations when working with types at runtime.
// ❌ Error: Cannot check for instance of erased type
fun <T> checkType(value: Any) {
if (value is T) { // type erasure — T is unknown
println("Type matches")
}
}
// ✅ Solution: pass Class as parameter
fun <T> checkTypeWithClass(
value: Any,
clazz: Class<T>
) {
if (clazz.isInstance(value)) {
println("Type matches")
}
}
In the example, checkType does not compile due to type erasure — the compiler does not know which type to substitute for T. In checkTypeWithClass, the problem is solved by explicitly passing Class<T>, but this requires boilerplate: every call is accompanied by .java or ::class.java. reified eliminates this boilerplate entirely.
The reified modifier is placed before the generic parameter in an inline function. The function must be inline — the compiler must be able to substitute the concrete type at the inlining stage.
inline fun <reified T> isA(value: Any): Boolean {
return value is T
}
fun main() {
println(isA<String>("Hello")) // true
println(isA<Int>("Hello")) // false
}
During compilation, the call isA<String>(“Hello”) is replaced with the check value is String. The call isA<Int>(“Hello”) becomes value is Int. The type is substituted literally, enabling the use of is, as, ::class and other operations unavailable with type erasure.
If you decompile the bytecode of isA<String>(“Hello”), IntelliJ IDEA will show approximately this result in Java: String.class.isInstance(value). Instead of a generic parameter, the compiler substituted the concrete java.lang.String.class — no reflection with type lookup by name, just a direct reference to the class.
The most common use of reified is type checking via the is operator. In a regular generic function, value is T does not compile. With reified, it works just like with a regular class: value is String, value is List<Int> (almost — with limitations for parameterized types).
inline fun <reified T> List<Any>.filterByType(): List<T> {
return this.filter { it is T }.map { it as T }
}
val mixed = listOf("a", 1, "b", 2)
val strings = mixed.filterByType<String>() // ["a", "b"]
val ints = mixed.filterByType<Int>() // [1, 2]
The extension function filterByType filters a list, keeping only elements of the specified type. Without reified, you would have to write filterByType<String>(list) with a Class<String> parameter. With reified, the call reads as a natural operation on a list, improving the readability of data processing chains.
According to the Kotlin Coroutines Guide (JetBrains, 2025), reified type checks are used in launch and async to pass the coroutine result type, avoiding explicit type specification in most cases.
reified provides access to T::class — a reference to KClass, from which you can obtain the Java Class via .java. This opens up possibilities for creating instances through reflection, working with serializers, and obtaining class annotations at runtime.
inline fun <reified T> createInstance(): T =
T::class.java.getDeclaredConstructor().newInstance()
// Usage
data class User(val name: String = "default")
val user = createInstance<User>()
// Serialization with Gson
inline fun <reified T> Gson.fromJson(json: String): T =
this.fromJson(json, T::class.java)
// Getting annotations
inline fun <reified T> hasAnnotation<A>(): Boolean where A : Annotation =
T::class.java.isAnnotationPresent(A::class.java)
The fromJson wrapper for Gson is a classic example of using reified in production. Instead of gson.fromJson(json, User::class.java), you can write gson.fromJson<User>(json). This may seem like a minor improvement, but in a project with hundreds of serialization calls, reified significantly reduces boilerplate and makes the code cleaner.
reified has limitations. First — it only works inside inline functions. If a function cannot be made inline (for example, it is recursive or too large), reified is unavailable. Second — reified cannot be used with suspend functions directly, only through inline wrappers.
Third — reified does not fully work with parameterized types. For example, filterByType<List<String>>() may produce unexpected results because for parameterized types, reified only preserves the raw type (List), without the generic arguments. For complete parameterized type checking, reflection with TypeToken is required.
| Operation | With reified | Without reified |
|---|---|---|
| value is T | ✅ Works | ❌ Compile error |
| T::class | ✅ Works | ❌ Compile error |
| List<String> is T | ⚠️ Raw type only | ❌ Error |
| Instance creation | ✅ Via reflection | ❌ Needs Class<T> |
| Suspend function | ❌ Only via inline wrapper | ❌ Not applicable |
For cases where reified is unavailable, use the pattern with explicit Class<T> or TypeToken from libraries (for example, Gson TypeToken or Jackson TypeReference). This approach works in any function but requires boilerplate and is less convenient.
Frequently Asked Questions
The compiler replaces the reified parameter T with the concrete type during function body inlining. If the function is not inline, the compiler has no place to substitute the type — a generic function call goes through a single bytecode where T is erased. Inline creates a separate bytecode copy for each type argument.
No, reified only applies to function parameters. For properties, use the inline fun <reified T> pattern with a return value, or explicitly pass Class<T> through a constructor. Extension properties also do not support reified.
reified supports nullable types: reified T : Any (non-null) and just reified T (can be nullable). For nullable types, T::class returns the class for the non-null version (String::class for String?). The value is T check accounts for null: if T = String?, then null is T = true.
Minimal. reified does not use reflection — the compiler substitutes the concrete type at the inlining stage. In bytecode, this is a direct class reference (ldc + checkcast/invokevirtual). There is no overhead compared to manually passing Class<T> — both approaches generate identical bytecode.
Yes, reified is actively used in Android. Bundle.getParcelable<T>(), Intent.getSerializableExtra<T>(), viewModels<T>() from Android KTX — all these functions use reified to avoid explicitly passing Class<T>. According to Google Android Docs (2025), reified is recommended for generic APIs where the type is needed at runtime.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also