# GraphQL Federation: What's the right way to use \_\_typename for fragment on Interface?

**URL:** <https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004>\
**Category:** API Design, Strategy & Governance\
**Tags:** federation\
**Created:** [August 26, 2026, 12:22am UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004 "2026-08-26T00:22:46Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![yuhanz](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/yuhanz/32/6597_2.png) [@yuhanz](https://community.apollographql.com/u/yuhanz)\
**Post date:** [August 26, 2026, 12:22am UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004/1 "2026-08-26T00:22:46Z")

</div>

We are upgrading our GraphQL Federation to the latest “@apollo/gateway”: “2.14.4” and find out that it handles fragment on interface differently than the older version.

In the older version, the query plan will interpret fragment to a flat call to subgraph, including the **typename field automatically. But in 2.14.4, the call to subgraph now receives the fragment directly without an interpretation and typename is no longer added. That breaks our feature as our subgraph only responds \_\_typename when \_\_typename is present in the input (and our existing queries didn’t include the** \_\_typename field)

So I wonder if this is a bug in the @apollo/gateway engine, or maybe our subgraph is encouraged to respond **typename ourselves on Interfaces. (I tested with letting subgraph to respond typename regardless of the input, the federation server worked well with it). What is the best practice to use** \_\_interface? Is it encourage to exist on fragment in the input queries?

---

<div class="post-metadata">

**Author:** ![yuhanz](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/yuhanz/32/6597_2.png) [@yuhanz](https://community.apollographql.com/u/yuhanz)\
**Post date:** [August 26, 2026, 11:23pm UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004/2 "2026-08-26T23:23:53Z")

</div>

This part of the code in query-planner-js/src/buildPlan.ts suggests that **typename should still be added. But in "** @apolloapolloapolloapollo/ **gateway": “2.14.4”, our query didn’t have** typename at all.

```auto
    const reuseQueryFragments = this.config.reuseQueryFragments ?? true;
    let fragments = operation.fragments;
    if (fragments && !fragments.isEmpty() && reuseQueryFragments) {
      // For all subgraph fetches we query `__typename` on every abstract types (see `FetchGroup.toPlanNode`) so if we want
      // to have a chance to reuse fragments, we should make sure those fragments also query `__typename` for every abstract type.
      fragments = addTypenameFieldForAbstractTypesInNamedFragments(fragments);
    } else {
      fragments = undefined;
    }

```

Something have caused this part of the code to be skipped. I wonder if it happened to do with the flag `this.config.debug.bypassPlannerForSingleSubgraph` before the block. I tried a query that makes requests to 2 subgraphs, and the problem persists. (So it wasn’t `bypassPlannerForSingleSubgraph)`

---

<div class="post-metadata">

**Author:** ![dkuc](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/dkuc/32/2892_2.png) [@dkuc](https://community.apollographql.com/u/dkuc)\
**Post date:** [September 8, 2026, 3:18pm UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004/3 "2026-09-08T15:18:44Z")

</div>

Hello 👋

Can you provide some additional information on what you are encountering and what problems this causes?

Query planner is responsible for generating an “efficient” plan on how to fulfill user request. This involves normalization of a query and then generation of 1+ subgraph fetches to fulfill the user request. Due to the normalization process your incoming queries may not be the same as the ones that gateway sends to the subgraph.

`bypassPlannerForSingleSubgraph` is an option to skip the planning entirely and pass in the original query to the target subgraph (i.e. skip normalization and query plan generation). This was specifically added for monographs (i.e. single GraphQL subgraph). In this situation, if your original query did not include `__typename` selection it won’t be include query either.

Referenced section of the code populates `__typename` defensively (in many cases it may not be needed) and its only used IF you choose a query plan option to `reuseQueryFragments` (this option attempts to preserve user provided fragments from the original query in the subgraph queries).

If you don’t enable any query optimizations OR use the option to `generateQueryFragments` ( **preferred mechanism** ) then this normalization is not applied at all and `__typename`s will only be included if needed.

Whether you are using `reuseQueryFragments`, `generateQueryFragments` or send uncompressed queries, query planner should generate valid queries. Your queries to the gateway/router should only include what is necessary for the clients. If additional data is necessary (e.g. through `@requires` or some type condition information) it will be populated by the query planner.

Thanks,  
Derek

---

<div class="post-metadata">

**Author:** ![yuhanz](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/yuhanz/32/6597_2.png) [@yuhanz](https://community.apollographql.com/u/yuhanz)\
**Post date:** [September 17, 2026, 7:18pm UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004/4 "2026-09-17T19:18:48Z")

</div>

Hi Derek,

Thanks for the reply. I setup a demo of the bug in [GitHub - yuhanz/bug-demo · GitHub](https://github.com/yuhanz/bug-demo)

Install the dependencies with `npm install --force` , and start the app with `sh start.sh`. The input form is available at: [http://localhost:4000/federation/](http://localhost:4000/federation/)

The app has 1 subgraph, which is based on schemas/subgraph.graphqls converted to schemas/supergraph2.sdl . I used src/MockGraphqlDataSource.js to emulate a subgraph backend where it responds json without **typename when it is not in the query and add** typename in the response when it appears in the query.

This query will demonstrate the bug:

```auto
fragment optionFields on IOption {
  id
   ... on ColorOption {
    primaryRGB
  }
}
{
      style(styleId: "401822600") {
        options {
      colors { ...optionFields }
      }
    }
}

```

The result isn’t rendered correctly with the RGB related field:

```auto
{
  "data": {
    "style": {
      "options": {
        "colors": [
          {
            "id": "1"
          },
          {
            "id": "2"
          }
        ]
      }
    }
  }
}

```

The query has to include \_\_typename in fragment to become a working query:

```auto
fragment optionFields on IOption {
  id
   ... on ColorOption {
    primaryRGB
  }
}
{
      style(styleId: "401822600") {
        options {
      colors { 
        __typename
        ...optionFields }
      }
    }
}

```

That gives the expected result:

```auto
{
  "data": {
    "style": {
      "options": {
        "colors": [
          {
            "__typename": "ColorOption",
            "id": "1",
            "primaryRGB": [
              255,
              255,
              255
            ]
          },
          {
            "__typename": "ColorOption",
            "id": "2",
            "primaryRGB": [
              9,
              9,
              9
            ]
          }
        ]
      }
    }
  }
}

```

Meanwhile, inline fragment always works, as it knows to include \_\_typename automatically:

```auto

{
      style(styleId: "401822600") {
        options {
      colors { 
        ... on ColorOption {
          primaryRGB
        } }
      }
    }
}

```

Quite unfortunately, I wasn’t able to identify at which combination of earlier versions of dependencies, fragment still worked. (It could be a combination of “@apollo/gateway” and “graphql”). But it used to be smart enough to know when to include \_\_typename automatically for fragment queries.

It seems a bug. Or maybe it has to do with my project setup / config parameters / dependency version? Could you guide, please?

Thank you.

Yuhan Zhang

---

<div class="post-metadata">

**Author:** ![yuhanz](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/yuhanz/32/6597_2.png) [@yuhanz](https://community.apollographql.com/u/yuhanz)\
**Post date:** [October 20, 2026, 1:03am UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004/5 "2026-10-20T01:03:58Z")

</div>

Hi,

I prepared a pull request, which added the \_\_typename on fragment query: [fixing the missing \_\_typename when fragment appears in the query by yuhanz · Pull Request #3475 · apollographql/federation · GitHub](https://github.com/apollographql/federation/pull/3475)

While the current main branch failed 1 test case for query-planner-js (which is the test of “only uses an @interfaceObject if it can”), this change has passed the particular test:

```auto
npm ci
npm test -- --runInBand query-planner-js/src/ __tests__ /buildPlan.interfaceObject.test.ts

 PASS @apollo/query-planner query-planner-js/src/ __tests__ /buildPlan.interfaceObject.test.ts
  ✓ avoids buffering @interfaceObject results that may have to filtered with lists (18 ms)
  ✓ handles @requires on concrete type of field provided by interface object (22 ms)
  ✓ handles @interfaceObject in nested entity (15 ms)
  ✓ handles @interfaceObject input rewrites when cloning dependency graph (22 ms)
  basic @key on interface/@interfaceObject handling
    ✓ can use a @key on an @interfaceObject type (8 ms)
    ✓ can use a @key on an interface "from" an @interfaceObject type (2 ms)
    ✓ only uses an @interfaceObject if it can (1 ms)
    ✓ does not rely on an @interfaceObject directly for `__typename` (2 ms)
    ✓ does not rely on an @interfaceObject directly if a specific implementation is requested (2 ms)
    ✓ can use a @key on an @interfaceObject type even for a concrete implementation (2 ms)
    ✓ handles query of an interface field (that is not on the `@interfaceObject`) for a specific implementation when query starts on the @interfaceObject (1 ms)

Test Suites: 1 passed, 1 total
Tests: 11 passed, 11 total
Snapshots: 11 passed, 11 total
Time: 1.03 s, estimated 2 s

```

Meanwhile, there are many other tests failing in the main branch. The CI test cases in the Github pull request doesn’t look clean. But I think the error is probably unrelated to the change? Could you guide on if this pull request can be considered?

Thank you.

---

<div class="post-metadata">

**Author:** ![Screen\_White](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/screen_white/32/6631_2.png) [@Screen\_White](https://community.apollographql.com/u/Screen_White)\
**Post date:** [October 28, 2026, 1:03am UTC](https://community.apollographql.com/t/graphql-federation-whats-the-right-way-to-use-typename-for-fragment-on-interface/10004/6 "2026-10-28T01:03:23Z")

</div>

The reproduction makes this look more like a query planning issue than something the subgraph should work around.

What’s interesting is that the inline fragment works, while the named fragment loses `primaryRGB` unless `__typename` is explicitly selected.

I’d compare the actual subgraph fetch operations generated with `reuseQueryFragments` enabled and disabled, using the same schema and input query. That might help isolate whether fragment reuse is dropping the type information needed to evaluate the concrete type condition.

I’d also check whether the gateway receives `__typename` internally but removes it from the final response, or whether it never requests it from the subgraph in the first place. Those would point to different stages of the problem.

I wouldn’t change the subgraph to return extra fields unconditionally just to work around this. The query planner should be responsible for requesting the information it needs.
