Solving Type Erasure in Kotlin with Inline Reified Parameters
Learn how Kotlin's inline functions and reified type parameters overcome JVM type erasure to create cleaner, type-safe APIs without the boilerplate of passing Class objects.
14 Mar 2026, 11:19 UTC

The Runtime Type Gap
In standard JVM generics, type information is erased at runtime. If you define a function as <T> fun process(item: T), the compiled bytecode doesn't know if T is a String, an Int, or a custom User object. This "type erasure" makes it impossible to perform checks like item is T or to instantiate T::class.java without passing the class explicitly as a parameter.
Passing Class<T> manually is the traditional workaround, but it creates verbose APIs and repetitive boilerplate. Kotlin solves this by combining inline functions with the reified keyword, allowing the compiler to "remember" the type at the call site.
How Inlining Enables Reification
An inline function tells the Kotlin compiler to copy the function's bytecode directly into the place where the function is called, rather than creating a standard method call. When you mark a type parameter as reified, the compiler can replace the generic placeholder T with the actual concrete type used during that specific call.
Because the code is pasted directly into the calling context, the specific type is known at that exact point in the bytecode. This eliminates the need for reflection or passing class literals, resulting in cleaner code and slightly better performance by removing the overhead of an additional function jump.
Practical Example: A Type-Safe JSON Parser
Consider a scenario where you need to deserialize a JSON string into a specific object. Without reified types, you would have to pass the class manually to your parser.
The Traditional Approach (Verbose)
fun <T> parseJson(json: String, clazz: Class<T>): T {
return Gson().fromJson(json, clazz)
}
// Usage
val user = parseJson(jsonString, User::class.java)
The Reified Approach (Clean)
By using inline and reified, you can hide the class parameter entirely:
inline fun <reified T> parseJson(json: String): T {
return Gson().fromJson(json, T::class.java)
}
// Usage
val user: User = parseJson(jsonString)
In the second example, the compiler sees parseJson<User> and effectively writes Gson().fromJson(jsonString, User::class.java) directly into your calling code.
Trade-offs and Limitations
While reified types simplify APIs, they are not a "silver bullet." There are three primary constraints to keep in mind:
- Bytecode Bloat: Because the code is copied at every call site, heavily used inline functions with large bodies can significantly increase the size of your final binary (DEX or JAR files).
- Java Interoperability: Java does not support inlining or reification. You cannot call a
reifiedfunction from Java code; it is a Kotlin-exclusive feature. - Visibility Restrictions: Inline functions cannot access
privateorinternalmembers of a class unless those members are also marked asinternaland the function is inside the same module.
Verification and Diagnostics
To verify that a function is actually being inlined and the type is being reified, you can inspect the compiled bytecode. Use the javap tool provided with the JDK on your compiled .class file:
# Run this in your terminal on the compiled class file
javap -c MyClassName.class
If the function was inlined, you will notice that the call to the reified function is missing from the bytecode, and the logic (including the concrete class reference) is embedded directly within the calling method. If you see an invokestatic or invokevirtual call to the utility function, it was not inlined.
Decision Matrix: When to use Reified
| Scenario | Use Reified? | Reasoning |
|---|---|---|
Generic Type Checking (is T) |
Yes | Impossible with standard generics. |
| Passing Class to Library (e.g., Retrofit/Gson) | Yes | Reduces boilerplate significantly. |
| Large, Complex Logic Blocks | No | Avoids excessive bytecode bloat. |
| Java-compatible Library API | No | Java cannot call reified functions. |
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.