fun buildClassSerialDescriptor(    serialName: String,     vararg typeParameters: SerialDescriptor,     builderAction: ClassSerialDescriptorBuilder.() -> Unit = {}): SerialDescriptor

Builder for SerialDescriptor. The resulting descriptor will be uniquely identified by the given serialName, typeParameters and elements structure described in builderAction function.


// Class with custom serializer and custom serial descriptor
class Data(
val intField: Int, // This field is ignored by custom serializer
val longField: Long, // This field is written as long, but in serialized form is named as "_longField"
val stringList: List<String> // This field is written as regular list of strings
val nullableInt: Int?
// Descriptor for such class:
SerialDescriptor("my.package.Data") {
// intField is deliberately ignored by serializer -- not present in the descriptor as well
element<Long>("_longField") // longField is named as _longField
element("stringField", listDescriptor<String>())
element("nullableInt", descriptor<Int>().nullable)

Example for generic classes:

class BoxedList<T>(val list: List<T>)

class CustomSerializer<T>(tSerializer: KSerializer<T>): KSerializer<BoxedList<T>> {
// here we use tSerializer.descriptor because it represents T
override val descriptor = SerialDescriptor("pkg.BoxedList", CLASS, tSerializer.descriptor) {
// here we have to wrap it with List first, because property has type List<T>
element("list", ListSerializer(tSerializer).descriptor) // or listSerialDescriptor(tSerializer.descriptor)