Tag typed data in JSON. By convention.
{
"#type": "Circle",
"radius": 4
}
When serializing a discriminated union, sum type, or polymorphic type to JSON,
use #type as the discriminator property.
The value is a logical tag name in PascalCase. Never a fully-qualified class name.
Purely optional. Completely compatible. Standard JSON.
The need for a type discriminator in JSON is well established. Everyone does it. Nobody agreed on how.
| Field | Used by | Purpose |
|---|---|---|
type | everywhere | discriminator, but collides with domain fields |
$type | .NET, uPickle | polymorphic type discriminator |
@type | JSON-LD | linked data node type |
__typename | GraphQL | concrete type in union responses |
Four ecosystems, same idea, four different names. #type is the simple, neutral answer.
# is valid in JSON property names, has no reserved meaning in any specification,
and reads naturally as "tag".
#type. The name is fixed and not configurable at the protocol level.#type is a logical tag name in PascalCase. It is never a runtime class name, fully-qualified path, or namespace-prefixed identifier.#type and the variant's fields sit as sibling properties in the same JSON object.#type.#type as the first property. Consumers must not depend on property order.{"#type": "Circle", "radius": 4}
{"#type": "Rectangle", "width": 10, "height": 5}
{"#type": "Car", "make": "Toyota"}
{"#type": "Truck", "payloadTons": 5}
Reference implementations exist for 12 languages, each wrapping the ecosystem's dominant JSON library. See the project on GitHub.