skip to content

What is the __typename meta-field in GraphQL, and where can a client select it?

level: juniorimportance: must knowfreq 66%

answer

  1. A field no schema author wrote
  2. Answers which type this really is
  3. Concrete object type, never the abstract one
  4. Returns String!, needs no arguments
  5. Forbidden only at a subscription root

basics

~20 s

__typename is a built-in meta-field selectable in any object, interface or union selection set. It returns the name of the concrete object type the server resolved, as a non-null String, so a client can tell which type it received.

solid answer

~50 s

`__typename` is a meta-field: the query language provides it, no schema declares it, and the double-underscore prefix is reserved so a schema cannot collide with it. It is selectable in any selection set on an object, interface or union type — at the root, at any depth, inside named and inline fragments — and it returns `String!` holding the name of the **concrete object type** that was resolved, never the interface or union you selected through. That makes it the only reliable discriminator when a field returns an abstract type: a union has no fields of its own, so `__typename` plus inline fragments is the entire toolkit. The specification carves out one exception: type name introspection is not available at the **root** of a subscription operation. And because it is implicit, it never shows up among a type's fields in an introspection result.

code

graphql · 8 lines
graphql
query MuseumSearch {
  search(term: "lute") {
    __typename
    ... on Artwork { title yearCompleted }
    ... on Exhibition { title opensOn }
    ... on Curator { fullName }
  }
}

go deeper

for a junior

Recall that __typename exists in every object, interface and union selection set, needs no declaration, and returns the resolved type's name as a String. Be ready to add it to a query on the spot when asked to tell union members apart.

for a middle

Explain that the value is the concrete object type, never the abstract type you selected through, and that meta-fields are implicit — they never appear in a type's introspected field list or in printed SDL.

for a senior

Show where you insist on it in practice: every selection over an abstract type, and every payload a normalized client cache stores, since keying on type name plus identifier is the common convention that prevents cross-type collisions. Know the subscription-root restriction.

for a principal

Own the house convention: whether every selection set in the organisation's documents carries __typename by default, what that adds to payload size at your volumes, and which shared tooling silently assumes it is present.

## A field the schema never declares Every GraphQL selection set that sits on an **object, interface or union** type carries one extra field that no schema author wrote: `__typename`. It takes no arguments, it is always selectable, and it always returns `String!` — the name of the **concrete object type** the server actually resolved at that position. The specification calls this a *meta-field*: it belongs to the query language rather than to your schema, and the double-underscore prefix is reserved by the specification precisely so that a schema can never define a name that collides with it. Consider a museum collection graph whose search field returns a union: ```graphql union SearchResult = Artwork | Exhibition | Curator type Query { search(term: String!): [SearchResult!]! } ``` A caller asking for `search(term: "lute")` gets a list back, but a union declares no fields of its own — there is nothing selectable on `SearchResult` except `__typename` and inline fragments. The discriminator is therefore not a nicety; it is the only thing in the response body that tells the caller which branch each element took. ## Concrete, always The most common misconception is that `__typename` echoes the type you *selected through*. It does not. If a field is declared to return the interface `CollectionItem` and the server resolves a `Painting`, `__typename` is `"Painting"`. An interface or union name never appears as a `__typename` value, because no value is ever *of* an abstract type at runtime — an abstract type is a contract, and every value that satisfies it is some object type. (How the server decides which object type a value is belongs to execution, not to introspection.) This is what makes the meta-field load-bearing on the client side. A caller cannot infer the type from which fields came back: two union members can legitimately expose the same field names, and a field the caller did not select is simply absent, so absence proves nothing. It is also why the widespread — **conventional, not specified** — practice in normalized client caches is to key each stored object on its type name together with an identifier. A museum client that keyed on the identifier alone once merged an `Artwork` and an `Exhibition` that both carried the id `10428`, and the list view rendered a row belonging to the other record entirely. Adding `__typename` to the key made the collision impossible. ## Where you may select it Anywhere an object, interface or union selection set exists: at the root of a query or mutation, at any depth below it, inside a named fragment, and inside an inline fragment. It cannot be selected on a scalar or an enum, for the ordinary reason that those have no selection set at all. The specification carves out exactly one exception: **type name introspection is not available at the root of a subscription operation.** A subscription's root selection set must name the single field whose event stream the operation subscribes to, and a meta-field is not such a field. Selecting `__typename` one level *inside* the subscription payload is perfectly fine — the restriction applies to the root selection set only. ## Not in the schema, not in the field list Because `__typename` is implicit, it never appears in the schema's own description of itself. An introspection result for `Artwork` lists the fields the author declared; `__typename` is not among them, and a printer that reconstructs SDL from that result will not print it. The same is true of the other meta-fields (`__schema` and `__type`) with respect to the query root type. Candidates who expect to see meta-fields in a type's field list have usually never read an introspection payload. ## Aliases and cost `__typename` behaves like any other field with respect to response keys, so it can be aliased: `kind: __typename` puts the value under `"kind"` instead. It costs nothing meaningful to resolve — the executor already knows the type of the value it is completing, so no user resolver runs. That cheapness is why some client tooling adds it automatically to every selection set it sends, and why many teams adopt the same habit by hand; both are conventions, not requirements. ## What a response looks like ```json { "__typename": "Artwork", "title": "Study of a Lutenist" } ``` Nothing distinguishes it structurally from a normal field: it is a key in the `data` object, at the position of the selection set that requested it. ## Watch for * Selecting over a union or interface **without** it, then trying to branch on which fields exist. * Assuming it returns the declared (abstract) type rather than the resolved object type. * Expecting it at the root of a subscription operation. * Expecting a schema to declare it, or an introspection result to list it.

  • If a field is declared to return an interface, does __typename give the interface name or the object type name?
    Always the concrete object type. No value is ever of an abstract type at runtime — an interface or union is a contract, and whatever the server resolved is some object type satisfying it. So a field typed `CollectionItem` that resolves a painting yields `"Painting"`, never `"CollectionItem"`.
  • Where can __typename not be selected?
    Nowhere that lacks a selection set — scalars and enums — and, by an explicit rule in the specification, not at the root selection set of a subscription operation, whose root must name the single event-stream field. Selecting it one level inside the subscription payload is fine.
  • Does __typename appear among a type's fields in an introspection result?
    No. Meta-fields are supplied by the query language, not by the type system, so `__Type.fields` for an object type lists only what the author declared. A printer that reconstructs SDL from introspection will not emit it either.

It is the label on the parcel rather than an item inside it: the courier prints it, the sender never packs it, and without it you would have to guess what is in the box from its shape.

saying these in an interview costs you the question

  • Says __typename must be declared in the schema
  • Thinks __typename returns the interface or union name
  • Claims you need a custom 'kind' field to discriminate a union
  • Believes it only works inside inline fragments
  • Expects __typename in a type's introspected field list

context