Question

Get a Runtime KClass from an Object in Kotlin

kotlinjavaclass

Question

In Java, I can determine a variable's runtime class by calling something.getClass(). In Kotlin, I know about something.javaClass, but I want the equivalent result as a KClass rather than a Java Class.

I have seen the Something::class syntax, but I need the KClass for the object currently stored in a variable. Does Kotlin provide this functionality?

Short Answer

Kotlin can obtain an object's runtime KClass with object::class. If you already have a Java Class, convert it with .kotlin, as in object.javaClass.kotlin. This page explains the difference between Kotlin and Java class representations, how runtime lookup works, and how to safely handle nullable values.

Concept

Kotlin has two closely related representations of class information:

  • KClass<T> is Kotlin's class metadata type, used by Kotlin reflection APIs.
  • Class<T> is Java's class metadata type, used by Java reflection and JVM APIs.

For an object held by a variable, use:

val runtimeType = value::class

value::class evaluates the object at runtime and returns the KClass of the object's actual class. It is Kotlin's direct equivalent of Java's value.getClass(), except that its result is a KClass.

open class Animal
class Dog : Animal()

val pet: Animal = Dog()

println(pet::class) // class Dog

Although pet is declared as Animal, the object currently stored in it is a Dog. Therefore pet::class returns Dog::class.

On the JVM, Kotlin also exposes Java class metadata:

val javaType: Class<*> = pet.javaClass
val kotlinType: kotlin.reflect.KClass<*> = pet.javaClass.kotlin

Use ::class when you want Kotlin-oriented metadata. Use javaClass when an API expects java.lang.Class.

Mental Model

Think of a variable as a labelled parking space and an object as the vehicle parked in it.

  • The variable's declared type is the sign above the space: Animal.
  • The runtime object type is the vehicle actually parked there: Dog.

pet::class looks at the vehicle currently in the space, so it reports Dog::class.

By contrast, Animal::class does not inspect a variable at all. It refers directly to the class named Animal, like reading a class label from a blueprint.

Take Quiz

Syntax and Examples

Use expression::class to retrieve an object's runtime Kotlin class.

class User(val name: String)

val user = User("Mina")
val type = user::class

println(type)           // class User
println(type.simpleName) // User

user is an expression containing an object. user::class returns a KClass<User>.

For a value whose declared type is a parent class or interface, the returned class still describes the concrete runtime object:

interface PaymentMethod
class CardPayment : PaymentMethod

val method: PaymentMethod = CardPayment()

println(method::class.simpleName) // CardPayment

You can also convert from a Java Class when needed:

val kotlinClass = method.javaClass.kotlin
println(kotlinClass.simpleName) // CardPayment

For normal non-null values, prefer method::class because it directly communicates that you want a Kotlin class reference.

Step by Step Execution

Consider this example:

open class Message
class EmailMessage : Message()

fun main() {
    val message: Message = EmailMessage()
    val type = message::class

    println(type.simpleName)
}

Execution steps:

  1. Message is declared as a base class.
  2. EmailMessage inherits from Message.
  3. The variable message is declared as Message, so code can treat it as any kind of message.
  4. An EmailMessage object is assigned to message.
  5. message::class inspects that object at runtime and produces EmailMessage::class.
  6. type.simpleName reads the simple name from the resulting KClass.
  7. The program prints EmailMessage.

The declared type (Message) and runtime type (EmailMessage) can be different. ::class on an object reports the runtime type.

Real World Use Cases

Runtime KClass values are useful when code must inspect or route objects dynamically.

  • Logging and diagnostics: Include the runtime type in an error message.

    fun logUnexpected(value: Any) {
        println("Unexpected value type: ${value::class.qualifiedName}")
    }
    
  • Serialization and deserialization: A framework may select a serializer based on a value's runtime type.

  • Dependency injection: A container can use KClass keys to find registered services.

    val services: Map<kotlin.reflect.KClass<*>, Any> = mapOf(
        String::class to "configured value"
    )
    
  • Plugin or command systems: Determine what concrete implementation was supplied.

  • Validation and debugging: Detect unexpected values returned from an API or stored in a collection.

Do not use runtime class checks when regular polymorphism is sufficient. For example, calling message.send() is usually better than checking whether message::class == EmailMessage::class and branching manually.

Take Quiz

Real Codebase Usage

In production Kotlin code, class references often appear in validation, registries, and boundaries between generic code and concrete implementations.

Validate a runtime type

When exact type identity matters, compare KClass values:

fun acceptsOnlyStrings(value: Any): Boolean {
    return value::class == String::class
}

For inheritance-aware checks, use is instead:

fun printIfMessage(value: Any) {
    if (value is Message) {
        println("This is a message")
    }
}

is is usually more readable and supports subclasses. Exact KClass comparison does not.

Use class references as registry keys

class ServiceRegistry {
    private val services = mutableMapOf<kotlin.reflect.KClass<*>, Any>()

    fun register(service: Any) {
        services[service::class] = service
    }

    fun find(type: kotlin.reflect.KClass<*>): Any? = services[type]
}

Handle nullable inputs with a guard clause

A nullable value has no runtime class when it is null. Return early before reading ::class:

fun describe(value: Any?): String {
    if (value == null) return "No value"
    return "Runtime type: ${value::class.simpleName}"
}

This makes the non-null requirement explicit and prevents errors.

Common Mistakes

Confusing a class literal with an object's class

class User
val user = User()

println(User::class) // The KClass for the named User class
println(user::class) // The runtime KClass for the object in user

Both may produce the same result in this simple example, but they mean different things. User::class is known from the source code; user::class examines the value at runtime.

Calling ::class on a nullable value

This is unsafe because the value may be null:

val value: Any? = null
// val type = value::class // Not valid for a nullable receiver

Check for null first:

val type = value?.let { it::class }
println(type) // null

Expecting the declared type instead of the runtime type

open class Animal
class Cat : Animal()

val animal: Animal = Cat()
println(animal::class.simpleName) // Cat, not Animal

If you need the declared type, use the known class literal, such as Animal::class, rather than inspecting the object.

Mixing Class and KClass

The following types are not interchangeable:

val javaClass: Class<*> = "hello".javaClass
val kotlinClass: kotlin.reflect.KClass<*> = "hello"::class

Convert explicitly when required:

val asKClass = javaClass.kotlin
val asJavaClass = kotlinClass.java

Using class equality when is is the real requirement

// Too strict: does not allow subclasses of Animal
if (value::class == Animal::class) {
    println("Animal")
}

Use an is check for a type family:

if (value is Animal) {
    println("Animal or one of its subclasses")
}

Comparisons

ExpressionResultBest use
value::classKClass<out T> for the runtime objectKotlin reflection and runtime type reporting
TypeName::classKClass<TypeName> for a named typeReferencing a type known in source code
value.javaClassJava Class<out T> for the runtime objectJava APIs and Java reflection
value.javaClass.kotlinKClass<out T>Converting an existing Java Class result
type.javaJava Class<T>Passing a KClass to a Java API
value is TypeNameBooleanChecking whether a value is a type or subtype

::class versus is

Use ::class when you need the class object itself, perhaps to log it or use it as a map key.

Use is when you only need to make a type-based decision:

if (value is String) {
    println(value.length)
}

is String supports smart casts. Comparing value::class == String::class does not provide the same convenient smart cast and is less flexible for subclasses.

Take Quiz

Cheat Sheet

// Runtime KClass of a non-null object
val type = value::class

// KClass for a type written in source code
val type = String::class

// Runtime Java Class
val javaType = value.javaClass

// Convert Java Class to KClass
val kotlinType = value.javaClass.kotlin

// Convert KClass to Java Class
val javaType = String::class.java

// Safely get KClass from a nullable value
val typeOrNull = nullableValue?.let { it::class }

// Test a type or subtype; usually preferable for branching
if (value is String) {
    println(value.length)
}

Key rules:

  • value::class returns the object's runtime KClass.
  • NamedType::class refers to a type explicitly named in code.
  • null has no runtime class; handle it before using ::class.
  • Use is for subtype-aware conditional logic.
  • Use .java and .kotlin to cross the Kotlin/Java reflection boundary.

FAQ

How do I get the KClass of an object in Kotlin?

Use object::class:

val type = object::class

It returns the runtime KClass of the non-null object.

Is object::class the Kotlin equivalent of Java getClass()?

Yes. object::class is the direct Kotlin-style equivalent when you want a KClass. object.javaClass is the closer equivalent when you want Java's Class type.

What is the difference between MyType::class and value::class?

MyType::class references the class named in your code. value::class examines the current runtime object stored in value.

How can I get a KClass from javaClass?

Use the .kotlin extension property:

val type = value.javaClass.kotlin

Can I call ::class on a nullable variable?

Not directly. First ensure the value is non-null:

val type = value?.let { it::class }

This produces null when value is null.

Should I compare value::class to a class literal to check a type?

Only when you need an exact class match. Prefer value is SomeType for normal type checks because it includes subclasses and enables smart casts.

Do I need a reflection dependency to use ::class?

Basic class literals and runtime KClass references work in Kotlin. Some advanced reflection operations, such as detailed member inspection, require the kotlin-reflect library on JVM projects.

Take Quiz

Mini Project

Description

Build a small runtime type reporter for values received from an untyped source, such as decoded JSON, command-line input, or a generic event payload. The reporter demonstrates obtaining a value's KClass, handling null, and using is when behavior should apply to a whole type family.

Goal

Create a function that returns a useful description of any nullable value, including its runtime Kotlin class when present.

Requirements

Create a describeValue function that accepts Any?. Handle null without attempting to read its class. Include the runtime class simple name for non-null values. Add a special description for String values. Test the function with at least four different values.

Take Quiz

Keep learning

Related questions

View more