skip to content

What is KType in Kotlin reflection, and what does it represent that a KClass cannot?

level: juniorimportance: must knowfreq 55%

answer

  1. KType = type usage (List<String>?), KClass = declaration (List)
  2. Three parts: classifier, arguments, isMarkedNullable
  3. Generics survive in KType despite JVM erasure
  4. typeOf<T>() is the safe way to get one

basics

~20 s

KType describes a full type used in code, like List<String>?. It knows the type arguments and whether the type can be null. A KClass only knows the bare class (List), not its arguments or nullability.

solid answer

~40 s

KType is the reflection representation of a Kotlin type as written in source, e.g. List<String>?. It carries three things a KClass alone cannot: the classifier (the underlying KClass or type parameter via the classifier property), the type arguments (List<KTypeProjection> via arguments, capturing the String in List<String>), and nullability (isMarkedNullable, true for List<String>?). KClass only models the declaration of a class without generics or nullability, so List<String> and List<Int> share one KClass but are distinct KTypes. You obtain a KType most safely with typeOf<List<String>>() rather than building one by hand. KType is essential when you need the actual generic shape at runtime, for example in serialization libraries (kotlinx.serialization) that must distinguish List<String> from List<Int> despite JVM type erasure.

code

kotlin · 7 lines
kotlin
import kotlin.reflect.typeOf

val a = typeOf<List<String>>()
val b = typeOf<List<Int>>()
println(a == b)                 // false — different arguments
println(a.classifier == b.classifier) // true — same KClass (List)
println(typeOf<String>() == typeOf<String?>()) // false — nullability differs

go deeper

for a junior

Can state that KType represents a full type with generics and nullability, unlike KClass.

for a middle

Names classifier, arguments, isMarkedNullable and explains why serialization needs KType.

for a senior

Connects KType to JVM erasure and KTypeProjection/variance details.

for a principal

Frames KType as the runtime carrier of source type information that bridges erased JVM generics for library design.

## What KType is `KType` (in package `kotlin.reflect`) is the reflection model of a *type usage* — exactly the type as written at a use site, such as `List<String>?`, `Map<String, Int>`, or `Array<out Number>`. Contrast this with `KClass`, which models a *class declaration* (`List`, `Map`) without any generic arguments or nullability. ## The three pieces of information KType carries - **classifier** (`KType.classifier: KClassifier?`): the thing being instantiated — either a `KClass` (for an ordinary class) or a `KTypeParameter` (for a generic type variable like `T`). - **arguments** (`KType.arguments: List<KTypeProjection>`): the generic type arguments. For `List<String>` this is one `KTypeProjection` wrapping the `KType` for `String`. A `KTypeProjection` also records *variance* (`in`/`out`/invariant) and supports star projections (`*`). - **isMarkedNullable** (`KType.isMarkedNullable: Boolean`): whether the type was written with a trailing `?`. `String?` is marked nullable; `String` is not. ```kotlin import kotlin.reflect.typeOf val t = typeOf<List<String>?>() println(t.classifier) // class kotlin.collections.List println(t.isMarkedNullable) // true println(t.arguments) // [String] println(t.arguments[0].type) // kotlin.String ``` ## Why KClass is not enough The JVM erases generics, so at runtime `List<String>` and `List<Int>` are both just `List`. Their `KClass` is identical. But their `KType` differs because `KType` preserves the source-level generic arguments. This is precisely why libraries like **kotlinx.serialization** accept a `KType` (or use `typeOf<T>()`) instead of a `KClass` — they need to know it is a `List<String>` to serialize each element correctly. ## Equality Two `KType` instances are equal only if classifier, arguments, and nullability all match. So `typeOf<List<String>>() != typeOf<List<Int>>()` and `typeOf<String>() != typeOf<String?>()`.

  • Can two different KTypes share the same KClass?
    Yes. List<String> and List<Int> have the same classifier KClass (List) but are different KTypes because their arguments differ.
  • How do you read the element type of a List<String> KType?
    Through type.arguments[0].type, which gives the KType for String (or null for a star projection).

KClass is the blank form (a 'List'); KType is the filled-in form ('List of String, may be empty/null').

saying these in an interview costs you the question

  • Saying KType and KClass are the same thing
  • Claiming generics are always lost at runtime in Kotlin
  • Thinking KType ignores nullability
  • Confusing classifier with the type arguments

context