← Back to Kotlin Course | Chapter 11: Generics | Lesson 5 of 6

Type Erasure

Type erasure means that once your code is compiled, the JVM forgets exactly which generic type a container was holding, only remembering the container itself.

Generic Type Information Is Erased

Once compiled, the JVM no longer distinguishes between a List<String> and a List<Int> -- both are simply represented as a plain List at runtime, which is what 'type erasure' means.

Example: Generic Type Information Is Erased

markup
fun main() {
    val strings: List<Any> = listOf("a", "b")
    val numbers: List<Any> = listOf(1, 2)
    println("Same runtime class: ${strings::class == numbers::class}")
}

Why You Cannot Check is List<String>

Because the element type is erased, Kotlin does not allow checking is List<String> directly -- only whether something is a List at all, using a star projection like is List<*>.

Example: Why You Cannot Check is List<String>

markup
fun describe(value: Any) {
    if (value is List<*>) {
        println("It is some kind of List with ${value.size} elements")
    }
}

fun main() {
    describe(listOf(1, 2, 3))
    describe(listOf("a", "b"))
}

Working Around Erasure with reified

Because plain generic functions cannot see the real type at runtime, the reified keyword on an inline function's type parameter is the standard workaround when a runtime type check is genuinely needed.

Example: Working Around Erasure with reified

markup
inline fun <reified T> countOfType(items: List<Any>): Int = items.count { it is T }

fun main() {
    val mixed = listOf(1, "a", 2, "b", 3)
    println("Number of Strings: ${countOfType<String>(mixed)}")
}

Arrays Are Not Erased

Unlike generic collections, arrays in Kotlin (backed by JVM arrays) retain their component type information at runtime, so is Array<String>-style checks behave differently from generic collections.

Example: Arrays Are Not Erased

markup
fun main() {
    val stringArray: Array<String> = arrayOf("a", "b")
    println("Array component type: ${stringArray.javaClass.componentType}")
}
Common Mistakes
  1. Trying to check if (list is List<String>), which the compiler rejects since the element type is erased and cannot be checked at runtime.
  2. Assuming two List<Int> and List<String> are different runtime classes; at runtime they are both simply the same List class.
  3. Forgetting that arrays are an exception -- unlike generic collections, arrays retain their element type information at runtime (reified natively by the JVM).
Chapter Summary
  • At runtime, generic type parameters are erased -- a List<String> and a List<Int> are both just List once compiled.
  • You cannot check is List<String> directly; only an unchecked cast or a star-projected check like is List<*> is allowed.
  • Type erasure is a JVM-wide limitation, not specific to Kotlin, and it's why reified type parameters (with inline) exist as a workaround.
  • Arrays are an exception to erasure -- their component type is preserved by the JVM at runtime.
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.