diff --git a/docs/rtk-query/api/created-api/code-splitting.mdx b/docs/rtk-query/api/created-api/code-splitting.mdx
index 7af418413d..9e0d22e1c6 100644
--- a/docs/rtk-query/api/created-api/code-splitting.mdx
+++ b/docs/rtk-query/api/created-api/code-splitting.mdx
@@ -13,7 +13,7 @@ Each API slice allows [additional endpoint definitions to be injected at runtime
 
 The individual API slice endpoint definitions can also be split across multiple files. This is primarily useful for working with API slices that were [code-generated from an API schema file](../../usage/code-generation.mdx), allowing you to add additional custom behavior and configuration to a set of automatically-generated endpoint definitions.
 
-Each API slice object has `injectEndpoints` and `enhanceEndpoints` functions to support these use cases.
+Each API slice object has `injectEndpoints`, `addTagTypes` and `enhanceEndpoint` functions to support these use cases.
 
 ## `injectEndpoints`
 
@@ -46,29 +46,44 @@ Endpoints will not be overridden unless `overrideExisting` is set to `true`. If
 
 This method is primarily useful for code splitting and hot reloading.
 
-## `enhanceEndpoints`
+## `addTagTypes`
 
 #### Signature
 
 ```ts no-transpile
-const enhanceEndpoints = (endpointOptions: EnhanceEndpointsOptions) =>
-  EnhancedApiSlice
+const addTagTypes = (...newTags: readonly string[]) => EnhancedApiSlice
+```
 
-interface EnhanceEndpointsOptions {
-  addTagTypes?: readonly string[]
-  endpoints?: Record<string, Partial<EndpointDefinition>>
-}
+#### Description
+
+Accepts a number of new tags to add to the API slice.
+
+Returns an updated and enhanced version of the API slice object, with the new tags added.
+
+This is primarily useful for chaining before `injectEndpoints` or `enhanceEndpoint`, to add tags which can then be used by new/enhanced endpoints.
+
+## `enhanceEndpoint`
+
+#### Signature
+
+```ts no-transpile
+const enhanceEndpoint = (
+  endpointName: string,
+  partialDefinition:
+    | Partial<EndpointDefinition>
+    | ((definition: EndpointDefinition) => void)
+) => EnhancedApiSlice
 ```
 
 #### Description
 
-Any provided tag types or endpoint definitions will be merged into the existing endpoint definitions for this API slice. Unlike `injectEndpoints`, the partial endpoint definitions will not _replace_ existing definitions, but are rather merged together on a per-definition basis (ie, `Object.assign(existingEndpoint, newPartialEndpoint)`).
+Provided partial definition will be merged into the existing endpoint definition for this API slice. Unlike `injectEndpoints`, the partial endpoint definition will not _replace_ the existing definition, but is rather merged together (i.e. `Object.assign(existingEndpoint, newPartialEndpoint)`).
 
 Returns an updated and enhanced version of the API slice object, containing the combined endpoint definitions.
 
 This is primarily useful for taking an API slice object that was code-generated from an API schema file like OpenAPI, and adding additional specific hand-written configuration for cache invalidation management on top of the generated endpoint definitions.
 
-For example, `enhanceEndpoints` can be used to modify caching behavior by changing the values of `providesTags`, `invalidatesTags`, and `keepUnusedDataFor`:
+For example, `enhanceEndpoint` can be used to modify caching behavior by changing the values of `providesTags`, `invalidatesTags`, and `keepUnusedDataFor`:
 
 ```ts
 // file: api.ts noEmit
@@ -98,20 +113,17 @@ export const api = createApi({
 // file: enhanceEndpoints.ts
 import { api } from './api'
 
-const enhancedApi = api.enhanceEndpoints({
-  addTagTypes: ['User'],
-  endpoints: {
-    getUserByUserId: {
-      providesTags: ['User'],
-    },
-    patchUserByUserId: {
-      invalidatesTags: ['User'],
-    },
-    // alternatively, define a function which is called with the endpoint definition as an argument
-    getUsers(endpoint) {
-      endpoint.providesTags = ['User']
-      endpoint.keepUnusedDataFor = 120
-    },
-  },
-})
+const enhancedApi = api
+  .addTagTypes('User')
+  .enhanceEndpoint('getUserByUserId', {
+    providesTags: ['User'],
+  })
+  .enhanceEndpoint('patchUserByUserId', {
+    invalidatesTags: ['User'],
+  })
+  // alternatively, define a function which is called with the endpoint definition as an argument
+  .enhanceEndpoint('getUsers', (endpoint) => {
+    endpoint.providesTags = ['User']
+    endpoint.keepUnusedDataFor = 120
+  })
 ```
diff --git a/docs/rtk-query/api/created-api/overview.mdx b/docs/rtk-query/api/created-api/overview.mdx
index 5db80993b2..09236f6fbc 100644
--- a/docs/rtk-query/api/created-api/overview.mdx
+++ b/docs/rtk-query/api/created-api/overview.mdx
@@ -42,7 +42,13 @@ type Api = {
 
   // Code splitting and generation
   injectEndpoints: (options: InjectEndpointsOptions) => UpdatedApi
-  enhanceEndpoints: (options: EnhanceEndpointsOptions) => UpdatedApi
+  addTagTypes: (...newTags: readonly string[]) => UpdatedApi
+  enhanceEndpoint: (
+    endpointName: string,
+    partialDefinition:
+      | Partial<EndpointDefinition>
+      | ((definition: EndpointDefinition) => void)
+  ) => UpdatedApi
 
   // Utilities
   utils: {
@@ -118,7 +124,7 @@ Each API slice allows [additional endpoint definitions to be injected at runtime
 
 The individual API slice endpoint definitions can also be split across multiple files. This is primarily useful for working with API slices that were [code-generated from an API schema file](../../usage/code-generation.mdx), allowing you to add additional custom behavior and configuration to a set of automatically-generated endpoint definitions.
 
-Each API slice object has `injectEndpoints` and `enhanceEndpoints` functions to support these use cases.
+Each API slice object has `injectEndpoints`, `addTagTypes` and `enhanceEndpoint` functions to support these use cases.
 
 :::info API Reference
 
diff --git a/docs/rtk-query/usage/code-generation.mdx b/docs/rtk-query/usage/code-generation.mdx
index 31ec095875..c01137a689 100644
--- a/docs/rtk-query/usage/code-generation.mdx
+++ b/docs/rtk-query/usage/code-generation.mdx
@@ -69,7 +69,7 @@ That will result in all generated endpoints having `providesTags`/`invalidatesTa
 
 Note that this will only result in string tags with no ids, so it might lead to scenarios where too much is invalidated and unneccessary requests are made on mutation.
 
-In that case it is still recommended to manually specify tags by using [`enhanceEndpoints`](../api/created-api/code-splitting.mdx) on top of the generated api and manually declare `providesTags`/`invalidatesTags`.
+In that case it is still recommended to manually specify tags by using [`addTagTypes` and `enhanceEndpoint`](../api/created-api/code-splitting.mdx) on top of the generated api and manually declare `providesTags`/`invalidatesTags`.
 
 ### Programmatic usage
 
diff --git a/examples/query/react/kitchen-sink/src/app/services/api.ts b/examples/query/react/kitchen-sink/src/app/services/api.ts
index 0cd4e2e692..e042f3a51a 100644
--- a/examples/query/react/kitchen-sink/src/app/services/api.ts
+++ b/examples/query/react/kitchen-sink/src/app/services/api.ts
@@ -47,9 +47,3 @@ export const api = createApi({
    */
   endpoints: () => ({}),
 })
-
-export const enhancedApi = api.enhanceEndpoints({
-  endpoints: () => ({
-    getPost: () => 'test',
-  }),
-})
diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/README.md b/packages/rtk-codemods/transforms/enhanceEndpoint/README.md
new file mode 100644
index 0000000000..42242a3906
--- /dev/null
+++ b/packages/rtk-codemods/transforms/enhanceEndpoint/README.md
@@ -0,0 +1,28 @@
+# enhanceEndpoint
+
+Transforms enhanceEndpoints calls into addTagType and enhanceEndpoint calls, in preparation for RTK 3.0.
+
+## Usage
+
+```
+npx @reduxjs/rtk-codemods enhanceEndpoint path/of/files/ or/some**/*glob.js
+
+# or
+
+yarn global add @reduxjs/rtk-codemods
+@reduxjs/rtk-codemods enhanceEndpoint path/of/files/ or/some**/*glob.js
+```
+
+## Local Usage
+
+```
+node ./bin/cli.js enhanceEndpoint path/of/files/ or/some**/*glob.js
+```
+
+## Input / Output
+
+<!--FIXTURES_TOC_START-->
+<!--FIXTURES_TOC_END-->
+
+<!--FIXTURES_CONTENT_START-->
+<!--FIXTURES_CONTENT_END-->
diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js
new file mode 100644
index 0000000000..4972286137
--- /dev/null
+++ b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.input.js
@@ -0,0 +1,38 @@
+const withTags = api.enhanceEndpoints({
+    addTagTypes: ['tag1']
+});
+
+const mutation2 = 'mutation2';
+
+const withPartials = withTags.enhanceEndpoints({
+    endpoints: {
+        query1: {
+            providesTags: ['tag1']
+        },
+        mutation1(definition) {
+            definition.invalidatesTags = ['tag1']
+        },
+        [mutation2]: (definition) => {}
+    }
+})
+
+const tags = ['tag1']
+
+const withBoth = api.enhanceEndpoints({
+    addTagTypes: tags,
+    endpoints: {
+        ["query1"]: {
+            providesTags: ['tag1']
+        },
+    }
+})
+
+const addTagTypes = tags
+
+const chained = api
+    .enhanceEndpoints({
+        addTagTypes
+    })
+    .injectEndpoints({
+        endpoints: () => {}
+    })
\ No newline at end of file
diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js
new file mode 100644
index 0000000000..a23264b143
--- /dev/null
+++ b/packages/rtk-codemods/transforms/enhanceEndpoint/__testfixtures__/basic.output.js
@@ -0,0 +1,22 @@
+const withTags = api.addTagTypes('tag1');
+
+const mutation2 = 'mutation2';
+
+const withPartials = withTags.enhanceEndpoint("query1", {
+    providesTags: ['tag1']
+}).enhanceEndpoint("mutation1", (definition) => {
+    definition.invalidatesTags = ['tag1']
+}).enhanceEndpoint(mutation2, (definition) => {})
+
+const tags = ['tag1']
+
+const withBoth = api.addTagTypes(...tags).enhanceEndpoint("query1", {
+    providesTags: ['tag1']
+})
+
+const addTagTypes = tags
+
+const chained = api.addTagTypes(...addTagTypes)
+    .injectEndpoints({
+        endpoints: () => {}
+    })
\ No newline at end of file
diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/index.ts b/packages/rtk-codemods/transforms/enhanceEndpoint/index.ts
new file mode 100644
index 0000000000..6bb39de8d3
--- /dev/null
+++ b/packages/rtk-codemods/transforms/enhanceEndpoint/index.ts
@@ -0,0 +1,126 @@
+import type {
+  Transform,
+  MemberExpression,
+  ObjectExpression,
+  RestElement,
+  JSCodeshift
+} from 'jscodeshift'
+
+type Prop = Extract<
+  ObjectExpression['properties'][number],
+  { value: unknown }
+>['value']
+
+const createAddTagTypesCall = (
+  j: JSCodeshift,
+  object: MemberExpression['object'],
+  addTagTypes: Prop
+) => {
+  const newCall = j.callExpression(
+    j.memberExpression(object, j.identifier('addTagTypes')),
+    []
+  )
+  if (addTagTypes.type === 'Identifier') {
+    newCall.arguments.push(j.spreadElement(addTagTypes))
+  } else if (addTagTypes.type === 'ArrayExpression') {
+    newCall.arguments = addTagTypes.elements.filter(
+      (el): el is Exclude<typeof el, RestElement | null> =>
+        !!(el && el.type !== 'RestElement')
+    )
+  }
+  return newCall
+}
+
+const transform: Transform = (file, api) => {
+  const j = api.jscodeshift
+
+  const root = j(file.source)
+
+  return root
+    .find(j.CallExpression, {
+      callee: {
+        property: {
+          name: 'enhanceEndpoints'
+        }
+      }
+    })
+    .forEach((path) => {
+      const callee = path.value.callee as MemberExpression
+      const [config] = path.value.arguments
+      if (config.type === 'ObjectExpression') {
+        let addTagTypes: Prop | undefined = undefined
+        let endpoints: Prop | undefined = undefined
+        for (const property of config.properties) {
+          if (
+            (property.type === 'ObjectProperty' ||
+              property.type === 'Property') &&
+            property.key.type === 'Identifier'
+          ) {
+            switch (property.key.name) {
+              case 'addTagTypes':
+                addTagTypes = property.value
+                break
+              case 'endpoints':
+                endpoints = property.value
+                break
+            }
+          }
+        }
+        if (!endpoints) {
+          if (!addTagTypes) {
+            return
+          }
+          // no endpoints - we can go ahead and replace
+          path.replace(createAddTagTypesCall(j, callee.object, addTagTypes))
+        } else {
+          let calleeObject = addTagTypes
+            ? createAddTagTypesCall(j, callee.object, addTagTypes)
+            : callee.object
+          if (endpoints.type === 'ObjectExpression') {
+            for (const endpointProp of endpoints.properties) {
+              if (endpointProp.type === 'ObjectProperty') {
+                const endpointName =
+                  endpointProp.key.type === 'Identifier' &&
+                  !endpointProp.computed
+                    ? j.stringLiteral(endpointProp.key.name)
+                    : endpointProp.key
+                calleeObject = j.callExpression(
+                  j.memberExpression(
+                    calleeObject,
+                    j.identifier('enhanceEndpoint')
+                  ),
+                  [endpointName, endpointProp.value as any]
+                )
+              } else if (endpointProp.type === 'ObjectMethod') {
+                const endpointName =
+                  endpointProp.key.type === 'Identifier'
+                    ? j.stringLiteral(endpointProp.key.name)
+                    : endpointProp.key
+                calleeObject = j.callExpression(
+                  j.memberExpression(
+                    calleeObject,
+                    j.identifier('enhanceEndpoint')
+                  ),
+                  [
+                    endpointName,
+                    j.arrowFunctionExpression(
+                      endpointProp.params,
+                      endpointProp.body
+                    )
+                  ]
+                )
+              }
+            }
+          }
+          path.replace(calleeObject)
+        }
+      }
+    })
+    .toSource({
+      arrowParensAlways: true
+    })
+}
+
+export const parser = 'tsx'
+
+export default transform
diff --git a/packages/rtk-codemods/transforms/enhanceEndpoint/test.js b/packages/rtk-codemods/transforms/enhanceEndpoint/test.js
new file mode 100644
index 0000000000..9196c9e1d6
--- /dev/null
+++ b/packages/rtk-codemods/transforms/enhanceEndpoint/test.js
@@ -0,0 +1,9 @@
+'use strict'
+
+const { runTransformTest } = require('codemod-cli')
+
+runTransformTest({
+  name: 'enhanceEndpoint',
+  path: require.resolve('./index.ts'),
+  fixtureDir: `${__dirname}/__testfixtures__/`
+})
diff --git a/packages/rtk-query-codegen-openapi/src/codegen.ts b/packages/rtk-query-codegen-openapi/src/codegen.ts
index 9ac4bd2274..899f3e95ef 100644
--- a/packages/rtk-query-codegen-openapi/src/codegen.ts
+++ b/packages/rtk-query-codegen-openapi/src/codegen.ts
@@ -53,10 +53,6 @@ export function generateCreateApiCall({
     true
   );
   if (tag) {
-    const enhanceEndpointsObjectLiteralExpression = factory.createObjectLiteralExpression(
-      [factory.createShorthandPropertyAssignment(factory.createIdentifier('addTagTypes'), undefined)],
-      true
-    );
     return factory.createVariableStatement(
       undefined,
       factory.createVariableDeclarationList(
@@ -70,10 +66,10 @@ export function generateCreateApiCall({
                 factory.createCallExpression(
                   factory.createPropertyAccessExpression(
                     factory.createIdentifier('api'),
-                    factory.createIdentifier('enhanceEndpoints')
+                    factory.createIdentifier('addTagTypes')
                   ),
                   undefined,
-                  [enhanceEndpointsObjectLiteralExpression]
+                  [factory.createSpreadElement(factory.createIdentifier('addTagTypes'))]
                 ),
                 factory.createIdentifier('injectEndpoints')
               ),
diff --git a/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap b/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap
index 3901adce96..ffdb0c61e8 100644
--- a/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap
+++ b/packages/rtk-query-codegen-openapi/test/__snapshots__/generateEndpoints.test.ts.snap
@@ -887,157 +887,147 @@ export const { useGetApiV1AnimalsQuery } = injectedRtkApi;
 exports[`yaml parsing > should be able to use read a yaml file 1`] = `
 "import { api } from "./tmp/emptyApi";
 export const addTagTypes = ["pet", "store", "user"] as const;
-const injectedRtkApi = api
-  .enhanceEndpoints({
-    addTagTypes,
-  })
-  .injectEndpoints({
-    endpoints: (build) => ({
-      updatePet: build.mutation<UpdatePetApiResponse, UpdatePetApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet\`,
-          method: "PUT",
-          body: queryArg.pet,
-        }),
-        invalidatesTags: ["pet"],
-      }),
-      addPet: build.mutation<AddPetApiResponse, AddPetApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet\`,
-          method: "POST",
-          body: queryArg.pet,
-        }),
-        invalidatesTags: ["pet"],
-      }),
-      findPetsByStatus: build.query<
-        FindPetsByStatusApiResponse,
-        FindPetsByStatusApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/pet/findByStatus\`,
-          params: { status: queryArg.status },
-        }),
-        providesTags: ["pet"],
-      }),
-      findPetsByTags: build.query<
-        FindPetsByTagsApiResponse,
-        FindPetsByTagsApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/pet/findByTags\`,
-          params: { tags: queryArg.tags },
-        }),
-        providesTags: ["pet"],
-      }),
-      getPetById: build.query<GetPetByIdApiResponse, GetPetByIdApiArg>({
-        query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }),
-        providesTags: ["pet"],
-      }),
-      updatePetWithForm: build.mutation<
-        UpdatePetWithFormApiResponse,
-        UpdatePetWithFormApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/pet/\${queryArg.petId}\`,
-          method: "POST",
-          params: { name: queryArg.name, status: queryArg.status },
-        }),
-        invalidatesTags: ["pet"],
+const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({
+  endpoints: (build) => ({
+    updatePet: build.mutation<UpdatePetApiResponse, UpdatePetApiArg>({
+      query: (queryArg) => ({ url: \`/pet\`, method: "PUT", body: queryArg.pet }),
+      invalidatesTags: ["pet"],
+    }),
+    addPet: build.mutation<AddPetApiResponse, AddPetApiArg>({
+      query: (queryArg) => ({
+        url: \`/pet\`,
+        method: "POST",
+        body: queryArg.pet,
       }),
-      deletePet: build.mutation<DeletePetApiResponse, DeletePetApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet/\${queryArg.petId}\`,
-          method: "DELETE",
-          headers: { api_key: queryArg.apiKey },
-        }),
-        invalidatesTags: ["pet"],
+      invalidatesTags: ["pet"],
+    }),
+    findPetsByStatus: build.query<
+      FindPetsByStatusApiResponse,
+      FindPetsByStatusApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/pet/findByStatus\`,
+        params: { status: queryArg.status },
       }),
-      uploadFile: build.mutation<UploadFileApiResponse, UploadFileApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet/\${queryArg.petId}/uploadImage\`,
-          method: "POST",
-          body: queryArg.body,
-          params: { additionalMetadata: queryArg.additionalMetadata },
-        }),
-        invalidatesTags: ["pet"],
+      providesTags: ["pet"],
+    }),
+    findPetsByTags: build.query<
+      FindPetsByTagsApiResponse,
+      FindPetsByTagsApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/pet/findByTags\`,
+        params: { tags: queryArg.tags },
       }),
-      getInventory: build.query<GetInventoryApiResponse, GetInventoryApiArg>({
-        query: () => ({ url: \`/store/inventory\` }),
-        providesTags: ["store"],
+      providesTags: ["pet"],
+    }),
+    getPetById: build.query<GetPetByIdApiResponse, GetPetByIdApiArg>({
+      query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }),
+      providesTags: ["pet"],
+    }),
+    updatePetWithForm: build.mutation<
+      UpdatePetWithFormApiResponse,
+      UpdatePetWithFormApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/pet/\${queryArg.petId}\`,
+        method: "POST",
+        params: { name: queryArg.name, status: queryArg.status },
       }),
-      placeOrder: build.mutation<PlaceOrderApiResponse, PlaceOrderApiArg>({
-        query: (queryArg) => ({
-          url: \`/store/order\`,
-          method: "POST",
-          body: queryArg.order,
-        }),
-        invalidatesTags: ["store"],
+      invalidatesTags: ["pet"],
+    }),
+    deletePet: build.mutation<DeletePetApiResponse, DeletePetApiArg>({
+      query: (queryArg) => ({
+        url: \`/pet/\${queryArg.petId}\`,
+        method: "DELETE",
+        headers: { api_key: queryArg.apiKey },
       }),
-      getOrderById: build.query<GetOrderByIdApiResponse, GetOrderByIdApiArg>({
-        query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }),
-        providesTags: ["store"],
+      invalidatesTags: ["pet"],
+    }),
+    uploadFile: build.mutation<UploadFileApiResponse, UploadFileApiArg>({
+      query: (queryArg) => ({
+        url: \`/pet/\${queryArg.petId}/uploadImage\`,
+        method: "POST",
+        body: queryArg.body,
+        params: { additionalMetadata: queryArg.additionalMetadata },
       }),
-      deleteOrder: build.mutation<DeleteOrderApiResponse, DeleteOrderApiArg>({
-        query: (queryArg) => ({
-          url: \`/store/order/\${queryArg.orderId}\`,
-          method: "DELETE",
-        }),
-        invalidatesTags: ["store"],
+      invalidatesTags: ["pet"],
+    }),
+    getInventory: build.query<GetInventoryApiResponse, GetInventoryApiArg>({
+      query: () => ({ url: \`/store/inventory\` }),
+      providesTags: ["store"],
+    }),
+    placeOrder: build.mutation<PlaceOrderApiResponse, PlaceOrderApiArg>({
+      query: (queryArg) => ({
+        url: \`/store/order\`,
+        method: "POST",
+        body: queryArg.order,
       }),
-      createUser: build.mutation<CreateUserApiResponse, CreateUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user\`,
-          method: "POST",
-          body: queryArg.user,
-        }),
-        invalidatesTags: ["user"],
+      invalidatesTags: ["store"],
+    }),
+    getOrderById: build.query<GetOrderByIdApiResponse, GetOrderByIdApiArg>({
+      query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }),
+      providesTags: ["store"],
+    }),
+    deleteOrder: build.mutation<DeleteOrderApiResponse, DeleteOrderApiArg>({
+      query: (queryArg) => ({
+        url: \`/store/order/\${queryArg.orderId}\`,
+        method: "DELETE",
       }),
-      createUsersWithListInput: build.mutation<
-        CreateUsersWithListInputApiResponse,
-        CreateUsersWithListInputApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/user/createWithList\`,
-          method: "POST",
-          body: queryArg.body,
-        }),
-        invalidatesTags: ["user"],
+      invalidatesTags: ["store"],
+    }),
+    createUser: build.mutation<CreateUserApiResponse, CreateUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user\`,
+        method: "POST",
+        body: queryArg.user,
       }),
-      loginUser: build.query<LoginUserApiResponse, LoginUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user/login\`,
-          params: { username: queryArg.username, password: queryArg.password },
-        }),
-        providesTags: ["user"],
+      invalidatesTags: ["user"],
+    }),
+    createUsersWithListInput: build.mutation<
+      CreateUsersWithListInputApiResponse,
+      CreateUsersWithListInputApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/user/createWithList\`,
+        method: "POST",
+        body: queryArg.body,
       }),
-      logoutUser: build.query<LogoutUserApiResponse, LogoutUserApiArg>({
-        query: () => ({ url: \`/user/logout\` }),
-        providesTags: ["user"],
+      invalidatesTags: ["user"],
+    }),
+    loginUser: build.query<LoginUserApiResponse, LoginUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user/login\`,
+        params: { username: queryArg.username, password: queryArg.password },
       }),
-      getUserByName: build.query<GetUserByNameApiResponse, GetUserByNameApiArg>(
-        {
-          query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }),
-          providesTags: ["user"],
-        },
-      ),
-      updateUser: build.mutation<UpdateUserApiResponse, UpdateUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user/\${queryArg.username}\`,
-          method: "PUT",
-          body: queryArg.user,
-        }),
-        invalidatesTags: ["user"],
+      providesTags: ["user"],
+    }),
+    logoutUser: build.query<LogoutUserApiResponse, LogoutUserApiArg>({
+      query: () => ({ url: \`/user/logout\` }),
+      providesTags: ["user"],
+    }),
+    getUserByName: build.query<GetUserByNameApiResponse, GetUserByNameApiArg>({
+      query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }),
+      providesTags: ["user"],
+    }),
+    updateUser: build.mutation<UpdateUserApiResponse, UpdateUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user/\${queryArg.username}\`,
+        method: "PUT",
+        body: queryArg.user,
       }),
-      deleteUser: build.mutation<DeleteUserApiResponse, DeleteUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user/\${queryArg.username}\`,
-          method: "DELETE",
-        }),
-        invalidatesTags: ["user"],
+      invalidatesTags: ["user"],
+    }),
+    deleteUser: build.mutation<DeleteUserApiResponse, DeleteUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user/\${queryArg.username}\`,
+        method: "DELETE",
       }),
+      invalidatesTags: ["user"],
     }),
-    overrideExisting: false,
-  });
+  }),
+  overrideExisting: false,
+});
 export { injectedRtkApi as enhancedApi };
 export type UpdatePetApiResponse = /** status 200 Successful operation */ Pet;
 export type UpdatePetApiArg = {
@@ -1217,34 +1207,30 @@ export const {
 exports[`yaml parsing > should generate params with non quoted keys if they don't contain special characters 1`] = `
 "import { api } from "./tmp/emptyApi";
 export const addTagTypes = ["StructureDefinition"] as const;
-const injectedRtkApi = api
-  .enhanceEndpoints({
-    addTagTypes,
-  })
-  .injectEndpoints({
-    endpoints: (build) => ({
-      getStructureDefinition: build.query<
-        GetStructureDefinitionApiResponse,
-        GetStructureDefinitionApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/StructureDefinition\`,
-          params: {
-            foo: queryArg.foo,
-            _foo: queryArg._foo,
-            "-bar-bar": queryArg["-bar-bar"],
-            _bar_bar: queryArg._bar_bar,
-            "foo:bar-foo.bar/foo": queryArg["foo:bar-foo.bar/foo"],
-            foo_bar: queryArg.fooBar,
-            namingConflict: queryArg.namingConflict,
-            naming_conflict: queryArg.naming_conflict,
-          },
-        }),
-        providesTags: ["StructureDefinition"],
+const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({
+  endpoints: (build) => ({
+    getStructureDefinition: build.query<
+      GetStructureDefinitionApiResponse,
+      GetStructureDefinitionApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/StructureDefinition\`,
+        params: {
+          foo: queryArg.foo,
+          _foo: queryArg._foo,
+          "-bar-bar": queryArg["-bar-bar"],
+          _bar_bar: queryArg._bar_bar,
+          "foo:bar-foo.bar/foo": queryArg["foo:bar-foo.bar/foo"],
+          foo_bar: queryArg.fooBar,
+          namingConflict: queryArg.namingConflict,
+          naming_conflict: queryArg.naming_conflict,
+        },
       }),
+      providesTags: ["StructureDefinition"],
     }),
-    overrideExisting: false,
-  });
+  }),
+  overrideExisting: false,
+});
 export { injectedRtkApi as enhancedApi };
 export type GetStructureDefinitionApiResponse =
   /** status 200 Success */ FhirJsonResource;
@@ -1274,157 +1260,147 @@ export const { useGetStructureDefinitionQuery } = injectedRtkApi;
 exports[`yaml parsing > should parse a yaml schema from a URL 1`] = `
 "import { api } from "./tmp/emptyApi";
 export const addTagTypes = ["pet", "store", "user"] as const;
-const injectedRtkApi = api
-  .enhanceEndpoints({
-    addTagTypes,
-  })
-  .injectEndpoints({
-    endpoints: (build) => ({
-      updatePet: build.mutation<UpdatePetApiResponse, UpdatePetApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet\`,
-          method: "PUT",
-          body: queryArg.pet,
-        }),
-        invalidatesTags: ["pet"],
-      }),
-      addPet: build.mutation<AddPetApiResponse, AddPetApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet\`,
-          method: "POST",
-          body: queryArg.pet,
-        }),
-        invalidatesTags: ["pet"],
-      }),
-      findPetsByStatus: build.query<
-        FindPetsByStatusApiResponse,
-        FindPetsByStatusApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/pet/findByStatus\`,
-          params: { status: queryArg.status },
-        }),
-        providesTags: ["pet"],
-      }),
-      findPetsByTags: build.query<
-        FindPetsByTagsApiResponse,
-        FindPetsByTagsApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/pet/findByTags\`,
-          params: { tags: queryArg.tags },
-        }),
-        providesTags: ["pet"],
-      }),
-      getPetById: build.query<GetPetByIdApiResponse, GetPetByIdApiArg>({
-        query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }),
-        providesTags: ["pet"],
-      }),
-      updatePetWithForm: build.mutation<
-        UpdatePetWithFormApiResponse,
-        UpdatePetWithFormApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/pet/\${queryArg.petId}\`,
-          method: "POST",
-          params: { name: queryArg.name, status: queryArg.status },
-        }),
-        invalidatesTags: ["pet"],
+const injectedRtkApi = api.addTagTypes(...addTagTypes).injectEndpoints({
+  endpoints: (build) => ({
+    updatePet: build.mutation<UpdatePetApiResponse, UpdatePetApiArg>({
+      query: (queryArg) => ({ url: \`/pet\`, method: "PUT", body: queryArg.pet }),
+      invalidatesTags: ["pet"],
+    }),
+    addPet: build.mutation<AddPetApiResponse, AddPetApiArg>({
+      query: (queryArg) => ({
+        url: \`/pet\`,
+        method: "POST",
+        body: queryArg.pet,
       }),
-      deletePet: build.mutation<DeletePetApiResponse, DeletePetApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet/\${queryArg.petId}\`,
-          method: "DELETE",
-          headers: { api_key: queryArg.apiKey },
-        }),
-        invalidatesTags: ["pet"],
+      invalidatesTags: ["pet"],
+    }),
+    findPetsByStatus: build.query<
+      FindPetsByStatusApiResponse,
+      FindPetsByStatusApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/pet/findByStatus\`,
+        params: { status: queryArg.status },
       }),
-      uploadFile: build.mutation<UploadFileApiResponse, UploadFileApiArg>({
-        query: (queryArg) => ({
-          url: \`/pet/\${queryArg.petId}/uploadImage\`,
-          method: "POST",
-          body: queryArg.body,
-          params: { additionalMetadata: queryArg.additionalMetadata },
-        }),
-        invalidatesTags: ["pet"],
+      providesTags: ["pet"],
+    }),
+    findPetsByTags: build.query<
+      FindPetsByTagsApiResponse,
+      FindPetsByTagsApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/pet/findByTags\`,
+        params: { tags: queryArg.tags },
       }),
-      getInventory: build.query<GetInventoryApiResponse, GetInventoryApiArg>({
-        query: () => ({ url: \`/store/inventory\` }),
-        providesTags: ["store"],
+      providesTags: ["pet"],
+    }),
+    getPetById: build.query<GetPetByIdApiResponse, GetPetByIdApiArg>({
+      query: (queryArg) => ({ url: \`/pet/\${queryArg.petId}\` }),
+      providesTags: ["pet"],
+    }),
+    updatePetWithForm: build.mutation<
+      UpdatePetWithFormApiResponse,
+      UpdatePetWithFormApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/pet/\${queryArg.petId}\`,
+        method: "POST",
+        params: { name: queryArg.name, status: queryArg.status },
       }),
-      placeOrder: build.mutation<PlaceOrderApiResponse, PlaceOrderApiArg>({
-        query: (queryArg) => ({
-          url: \`/store/order\`,
-          method: "POST",
-          body: queryArg.order,
-        }),
-        invalidatesTags: ["store"],
+      invalidatesTags: ["pet"],
+    }),
+    deletePet: build.mutation<DeletePetApiResponse, DeletePetApiArg>({
+      query: (queryArg) => ({
+        url: \`/pet/\${queryArg.petId}\`,
+        method: "DELETE",
+        headers: { api_key: queryArg.apiKey },
       }),
-      getOrderById: build.query<GetOrderByIdApiResponse, GetOrderByIdApiArg>({
-        query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }),
-        providesTags: ["store"],
+      invalidatesTags: ["pet"],
+    }),
+    uploadFile: build.mutation<UploadFileApiResponse, UploadFileApiArg>({
+      query: (queryArg) => ({
+        url: \`/pet/\${queryArg.petId}/uploadImage\`,
+        method: "POST",
+        body: queryArg.body,
+        params: { additionalMetadata: queryArg.additionalMetadata },
       }),
-      deleteOrder: build.mutation<DeleteOrderApiResponse, DeleteOrderApiArg>({
-        query: (queryArg) => ({
-          url: \`/store/order/\${queryArg.orderId}\`,
-          method: "DELETE",
-        }),
-        invalidatesTags: ["store"],
+      invalidatesTags: ["pet"],
+    }),
+    getInventory: build.query<GetInventoryApiResponse, GetInventoryApiArg>({
+      query: () => ({ url: \`/store/inventory\` }),
+      providesTags: ["store"],
+    }),
+    placeOrder: build.mutation<PlaceOrderApiResponse, PlaceOrderApiArg>({
+      query: (queryArg) => ({
+        url: \`/store/order\`,
+        method: "POST",
+        body: queryArg.order,
       }),
-      createUser: build.mutation<CreateUserApiResponse, CreateUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user\`,
-          method: "POST",
-          body: queryArg.user,
-        }),
-        invalidatesTags: ["user"],
+      invalidatesTags: ["store"],
+    }),
+    getOrderById: build.query<GetOrderByIdApiResponse, GetOrderByIdApiArg>({
+      query: (queryArg) => ({ url: \`/store/order/\${queryArg.orderId}\` }),
+      providesTags: ["store"],
+    }),
+    deleteOrder: build.mutation<DeleteOrderApiResponse, DeleteOrderApiArg>({
+      query: (queryArg) => ({
+        url: \`/store/order/\${queryArg.orderId}\`,
+        method: "DELETE",
       }),
-      createUsersWithListInput: build.mutation<
-        CreateUsersWithListInputApiResponse,
-        CreateUsersWithListInputApiArg
-      >({
-        query: (queryArg) => ({
-          url: \`/user/createWithList\`,
-          method: "POST",
-          body: queryArg.body,
-        }),
-        invalidatesTags: ["user"],
+      invalidatesTags: ["store"],
+    }),
+    createUser: build.mutation<CreateUserApiResponse, CreateUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user\`,
+        method: "POST",
+        body: queryArg.user,
       }),
-      loginUser: build.query<LoginUserApiResponse, LoginUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user/login\`,
-          params: { username: queryArg.username, password: queryArg.password },
-        }),
-        providesTags: ["user"],
+      invalidatesTags: ["user"],
+    }),
+    createUsersWithListInput: build.mutation<
+      CreateUsersWithListInputApiResponse,
+      CreateUsersWithListInputApiArg
+    >({
+      query: (queryArg) => ({
+        url: \`/user/createWithList\`,
+        method: "POST",
+        body: queryArg.body,
       }),
-      logoutUser: build.query<LogoutUserApiResponse, LogoutUserApiArg>({
-        query: () => ({ url: \`/user/logout\` }),
-        providesTags: ["user"],
+      invalidatesTags: ["user"],
+    }),
+    loginUser: build.query<LoginUserApiResponse, LoginUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user/login\`,
+        params: { username: queryArg.username, password: queryArg.password },
       }),
-      getUserByName: build.query<GetUserByNameApiResponse, GetUserByNameApiArg>(
-        {
-          query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }),
-          providesTags: ["user"],
-        },
-      ),
-      updateUser: build.mutation<UpdateUserApiResponse, UpdateUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user/\${queryArg.username}\`,
-          method: "PUT",
-          body: queryArg.user,
-        }),
-        invalidatesTags: ["user"],
+      providesTags: ["user"],
+    }),
+    logoutUser: build.query<LogoutUserApiResponse, LogoutUserApiArg>({
+      query: () => ({ url: \`/user/logout\` }),
+      providesTags: ["user"],
+    }),
+    getUserByName: build.query<GetUserByNameApiResponse, GetUserByNameApiArg>({
+      query: (queryArg) => ({ url: \`/user/\${queryArg.username}\` }),
+      providesTags: ["user"],
+    }),
+    updateUser: build.mutation<UpdateUserApiResponse, UpdateUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user/\${queryArg.username}\`,
+        method: "PUT",
+        body: queryArg.user,
       }),
-      deleteUser: build.mutation<DeleteUserApiResponse, DeleteUserApiArg>({
-        query: (queryArg) => ({
-          url: \`/user/\${queryArg.username}\`,
-          method: "DELETE",
-        }),
-        invalidatesTags: ["user"],
+      invalidatesTags: ["user"],
+    }),
+    deleteUser: build.mutation<DeleteUserApiResponse, DeleteUserApiArg>({
+      query: (queryArg) => ({
+        url: \`/user/\${queryArg.username}\`,
+        method: "DELETE",
       }),
+      invalidatesTags: ["user"],
     }),
-    overrideExisting: false,
-  });
+  }),
+  overrideExisting: false,
+});
 export { injectedRtkApi as enhancedApi };
 export type UpdatePetApiResponse = /** status 200 Successful operation */ Pet;
 export type UpdatePetApiArg = {
diff --git a/packages/toolkit/src/query/apiTypes.ts b/packages/toolkit/src/query/apiTypes.ts
index 99a24c4e87..058f0b4e47 100644
--- a/packages/toolkit/src/query/apiTypes.ts
+++ b/packages/toolkit/src/query/apiTypes.ts
@@ -3,17 +3,24 @@ import type {
   EndpointBuilder,
   EndpointDefinition,
   UpdateDefinitions,
+  QueryDefinition,
+  ResultTypeFrom,
+  QueryArgFrom,
+  MutationDefinition,
+  AddTagTypes,
+  EnhanceEndpoint,
 } from './endpointDefinitions'
 import type {
   UnionToIntersection,
   NoInfer,
   WithRequiredProp,
+  Id,
 } from './tsHelpers'
-import type { CoreModule } from './core/module'
 import type { CreateApiOptions } from './createApi'
 import type { BaseQueryFn } from './baseQueryTypes'
-import type { CombinedState } from './core/apiState'
+import type { CombinedState, MutationKeys, QueryKeys } from './core/apiState'
 import type { UnknownAction } from '@reduxjs/toolkit'
+import type { CoreModule } from './core/module'
 
 export interface ApiModules<
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -67,15 +74,13 @@ export interface ApiContext<Definitions extends EndpointDefinitions> {
   hasRehydrationInfo: (action: UnknownAction) => boolean
 }
 
-export type Api<
+export type BaseApiMethods<
   BaseQuery extends BaseQueryFn,
   Definitions extends EndpointDefinitions,
   ReducerPath extends string,
   TagTypes extends string,
   Enhancers extends ModuleName = CoreModule,
-> = UnionToIntersection<
-  ApiModules<BaseQuery, Definitions, ReducerPath, TagTypes>[Enhancers]
-> & {
+> = {
   /**
    * A function to inject the endpoints into the original API, but also give you that same API with correct types for these endpoints back. Useful with code-splitting.
    */
@@ -98,9 +103,107 @@ export type Api<
     TagTypes,
     Enhancers
   >
+  /**
+   *A function to add tag types to a generated API. Useful with code-generation.
+   */
+  addTagTypes<NewTagTypes extends string = never>(
+    ...addTagTypes: readonly NewTagTypes[]
+  ): Api<
+    BaseQuery,
+    AddTagTypes<Definitions, TagTypes | NewTagTypes>,
+    ReducerPath,
+    TagTypes | NewTagTypes,
+    Enhancers
+  >
+
+  /**
+   *A function to enhance a generated API endpoint with additional information. Useful with code-generation.
+   */
+  enhanceEndpoint<
+    QueryName extends QueryKeys<Definitions>,
+    ResultType = ResultTypeFrom<Definitions[QueryName]>,
+    QueryArg = QueryArgFrom<Definitions[QueryName]>,
+  >(
+    queryName: QueryName,
+    partialDefinition:
+      | Partial<
+          QueryDefinition<
+            QueryArg,
+            BaseQuery,
+            TagTypes,
+            ResultType,
+            ReducerPath
+          >
+        >
+      | ((
+          definition: QueryDefinition<
+            QueryArg,
+            BaseQuery,
+            TagTypes,
+            ResultType,
+            ReducerPath
+          >,
+        ) => void),
+  ): Api<
+    BaseQuery,
+    Id<
+      Omit<Definitions, QueryName> &
+        Record<
+          QueryName,
+          EnhanceEndpoint<Definitions[QueryName], QueryArg, ResultType>
+        >
+    >,
+    ReducerPath,
+    TagTypes,
+    Enhancers
+  >
+
   /**
    *A function to enhance a generated API with additional information. Useful with code-generation.
    */
+  enhanceEndpoint<
+    MutationName extends MutationKeys<Definitions>,
+    ResultType = ResultTypeFrom<Definitions[MutationName]>,
+    QueryArg = QueryArgFrom<Definitions[MutationName]>,
+  >(
+    mutationName: MutationName,
+    partialDefinition:
+      | Partial<
+          MutationDefinition<
+            QueryArg,
+            BaseQuery,
+            TagTypes,
+            ResultType,
+            ReducerPath
+          >
+        >
+      | ((
+          definition: MutationDefinition<
+            QueryArg,
+            BaseQuery,
+            TagTypes,
+            ResultType,
+            ReducerPath
+          >,
+        ) => void),
+  ): Api<
+    BaseQuery,
+    Id<
+      Omit<Definitions, MutationName> &
+        Record<
+          MutationName,
+          EnhanceEndpoint<Definitions[MutationName], QueryArg, ResultType>
+        >
+    >,
+    ReducerPath,
+    TagTypes,
+    Enhancers
+  >
+
+  /**
+   *A function to enhance a generated API with additional information. Useful with code-generation.
+   * @deprecated Please use `enhanceEndpoint` and `addTagType` instead
+   */
   enhanceEndpoints<
     NewTagTypes extends string = never,
     NewDefinitions extends EndpointDefinitions = never,
@@ -125,3 +228,14 @@ export type Api<
     Enhancers
   >
 }
+
+export type Api<
+  BaseQuery extends BaseQueryFn,
+  Definitions extends EndpointDefinitions,
+  ReducerPath extends string,
+  TagTypes extends string,
+  Enhancers extends ModuleName = CoreModule,
+> = UnionToIntersection<
+  ApiModules<BaseQuery, Definitions, ReducerPath, TagTypes>[Enhancers]
+> &
+  BaseApiMethods<BaseQuery, Definitions, ReducerPath, TagTypes, Enhancers>
diff --git a/packages/toolkit/src/query/core/buildInitiate.ts b/packages/toolkit/src/query/core/buildInitiate.ts
index 3823b14d79..e21bc31dc0 100644
--- a/packages/toolkit/src/query/core/buildInitiate.ts
+++ b/packages/toolkit/src/query/core/buildInitiate.ts
@@ -14,8 +14,8 @@ import type {
 } from '@reduxjs/toolkit'
 import type { SubscriptionOptions, RootState } from './apiState'
 import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'
-import type { Api, ApiContext } from '../apiTypes'
-import type { ApiEndpointQuery } from './module'
+import type { ApiContext, ApiModules } from '../apiTypes'
+import type { ApiEndpointQuery, CoreModule } from './module'
 import type { BaseQueryError, QueryReturnValue } from '../baseQueryTypes'
 import type { QueryResultSelectorResult } from './buildSelectors'
 import type { Dispatch } from 'redux'
@@ -204,7 +204,7 @@ export function buildInitiate({
   serializeQueryArgs: InternalSerializeQueryArgs
   queryThunk: QueryThunk
   mutationThunk: MutationThunk
-  api: Api<any, EndpointDefinitions, any, any>
+  api: ApiModules<any, EndpointDefinitions, any, any>[CoreModule]
   context: ApiContext<EndpointDefinitions>
 }) {
   const runningQueries: Map<
diff --git a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts
index 0a41e0174f..7cedd684c9 100644
--- a/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts
+++ b/packages/toolkit/src/query/core/buildMiddleware/cacheLifecycle.ts
@@ -13,9 +13,10 @@ import type { PatchCollection, Recipe } from '../buildThunks'
 import type {
   ApiMiddlewareInternalHandler,
   InternalHandlerBuilder,
-  PromiseWithKnownReason,
   SubMiddlewareApi,
 } from './types'
+import type { PromiseWithKnownReason } from '../../utils'
+import { promiseWithResolvers } from '../../utils'
 
 export type ReferenceCacheLifecycle = never
 
@@ -276,20 +277,22 @@ export const buildCacheLifecycleHandler: InternalHandlerBuilder = ({
 
     let lifecycle = {} as CacheLifecycle
 
-    const cacheEntryRemoved = new Promise<void>((resolve) => {
-      lifecycle.cacheEntryRemoved = resolve
-    })
-    const cacheDataLoaded: PromiseWithKnownReason<
+    let cacheEntryRemoved: Promise<void>
+    ;({ promise: cacheEntryRemoved, resolve: lifecycle.cacheEntryRemoved } =
+      promiseWithResolvers<void>())
+
+    const {
+      promise: cacheDataLoaded,
+      resolve,
+      reject,
+    } = promiseWithResolvers<
       { data: unknown; meta: unknown },
       typeof neverResolvedError
-    > = Promise.race([
-      new Promise<{ data: unknown; meta: unknown }>((resolve) => {
-        lifecycle.valueResolved = resolve
-      }),
-      cacheEntryRemoved.then(() => {
-        throw neverResolvedError
-      }),
-    ])
+    >()
+    lifecycle.valueResolved = resolve
+
+    cacheEntryRemoved.then(() => reject(neverResolvedError), reject)
+
     // prevent uncaught promise rejections from happening.
     // if the original promise is used in any way, that will create a new promise that will throw again
     cacheDataLoaded.catch(() => {})
diff --git a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts
index ebb47b771c..48e296eb9d 100644
--- a/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts
+++ b/packages/toolkit/src/query/core/buildMiddleware/queryLifecycle.ts
@@ -8,11 +8,11 @@ import { DefinitionType } from '../../endpointDefinitions'
 import type { QueryFulfilledRejectionReason } from '../../endpointDefinitions'
 import type { Recipe } from '../buildThunks'
 import type {
-  PromiseWithKnownReason,
-  PromiseConstructorWithKnownReason,
   InternalHandlerBuilder,
   ApiMiddlewareInternalHandler,
 } from './types'
+import type { PromiseWithKnownReason, PromiseWithResolvers } from '../../utils'
+import { promiseWithResolvers } from '../../utils'
 
 export type ReferenceQueryLifecycle = never
 
@@ -211,10 +211,14 @@ export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({
   const isRejectedThunk = isRejected(queryThunk, mutationThunk)
   const isFullfilledThunk = isFulfilled(queryThunk, mutationThunk)
 
-  type CacheLifecycle = {
-    resolve(value: { data: unknown; meta: unknown }): unknown
-    reject(value: QueryFulfilledRejectionReason<any>): unknown
-  }
+  type CacheLifecycle = Omit<
+    PromiseWithResolvers<
+      { data: unknown; meta: unknown },
+      QueryFulfilledRejectionReason<any>
+    >,
+    'promise'
+  >
+
   const lifecycleMap: Record<string, CacheLifecycle> = {}
 
   const handler: ApiMiddlewareInternalHandler = (action, mwApi) => {
@@ -226,15 +230,10 @@ export const buildQueryLifecycleHandler: InternalHandlerBuilder = ({
       const endpointDefinition = context.endpointDefinitions[endpointName]
       const onQueryStarted = endpointDefinition?.onQueryStarted
       if (onQueryStarted) {
-        const lifecycle = {} as CacheLifecycle
-        const queryFulfilled =
-          new (Promise as PromiseConstructorWithKnownReason)<
-            { data: unknown; meta: unknown },
-            QueryFulfilledRejectionReason<any>
-          >((resolve, reject) => {
-            lifecycle.resolve = resolve
-            lifecycle.reject = reject
-          })
+        const { promise: queryFulfilled, ...lifecycle } = promiseWithResolvers<
+          { data: unknown; meta: unknown },
+          QueryFulfilledRejectionReason<any>
+        >()
         // prevent uncaught promise rejections from happening.
         // if the original promise is used in any way, that will create a new promise that will throw again
         queryFulfilled.catch(() => {})
diff --git a/packages/toolkit/src/query/core/buildMiddleware/types.ts b/packages/toolkit/src/query/core/buildMiddleware/types.ts
index e2ab377b6c..94318fcbd8 100644
--- a/packages/toolkit/src/query/core/buildMiddleware/types.ts
+++ b/packages/toolkit/src/query/core/buildMiddleware/types.ts
@@ -7,7 +7,7 @@ import type {
   UnknownAction,
 } from '@reduxjs/toolkit'
 
-import type { Api, ApiContext } from '../../apiTypes'
+import type { ApiContext, ApiModules } from '../../apiTypes'
 import type {
   AssertTagTypes,
   EndpointDefinitions,
@@ -24,6 +24,7 @@ import type {
   QueryThunkArg,
   ThunkResult,
 } from '../buildThunks'
+import type { CoreModule } from '../module'
 
 export type QueryStateMeta<T> = Record<string, undefined | T>
 export type TimeoutId = ReturnType<typeof setTimeout>
@@ -47,7 +48,7 @@ export interface BuildMiddlewareInput<
   context: ApiContext<Definitions>
   queryThunk: QueryThunk
   mutationThunk: MutationThunk
-  api: Api<any, Definitions, ReducerPath, TagTypes>
+  api: ApiModules<any, EndpointDefinitions, ReducerPath, TagTypes>[CoreModule]
   assertTagType: AssertTagTypes
 }
 
@@ -89,50 +90,3 @@ export type ApiMiddlewareInternalHandler<Return = void> = (
 export type InternalHandlerBuilder<ReturnType = void> = (
   input: BuildSubMiddlewareInput,
 ) => ApiMiddlewareInternalHandler<ReturnType>
-
-export interface PromiseConstructorWithKnownReason {
-  /**
-   * Creates a new Promise with a known rejection reason.
-   * @param executor A callback used to initialize the promise. This callback is passed two arguments:
-   * a resolve callback used to resolve the promise with a value or the result of another promise,
-   * and a reject callback used to reject the promise with a provided reason or error.
-   */
-  new <T, R>(
-    executor: (
-      resolve: (value: T | PromiseLike<T>) => void,
-      reject: (reason?: R) => void,
-    ) => void,
-  ): PromiseWithKnownReason<T, R>
-}
-
-export interface PromiseWithKnownReason<T, R>
-  extends Omit<Promise<T>, 'then' | 'catch'> {
-  /**
-   * Attaches callbacks for the resolution and/or rejection of the Promise.
-   * @param onfulfilled The callback to execute when the Promise is resolved.
-   * @param onrejected The callback to execute when the Promise is rejected.
-   * @returns A Promise for the completion of which ever callback is executed.
-   */
-  then<TResult1 = T, TResult2 = never>(
-    onfulfilled?:
-      | ((value: T) => TResult1 | PromiseLike<TResult1>)
-      | undefined
-      | null,
-    onrejected?:
-      | ((reason: R) => TResult2 | PromiseLike<TResult2>)
-      | undefined
-      | null,
-  ): Promise<TResult1 | TResult2>
-
-  /**
-   * Attaches a callback for only the rejection of the Promise.
-   * @param onrejected The callback to execute when the Promise is rejected.
-   * @returns A Promise for the completion of the callback.
-   */
-  catch<TResult = never>(
-    onrejected?:
-      | ((reason: R) => TResult | PromiseLike<TResult>)
-      | undefined
-      | null,
-  ): Promise<T | TResult>
-}
diff --git a/packages/toolkit/src/query/createApi.ts b/packages/toolkit/src/query/createApi.ts
index 6e0ec61392..e460d5e2bb 100644
--- a/packages/toolkit/src/query/createApi.ts
+++ b/packages/toolkit/src/query/createApi.ts
@@ -311,26 +311,34 @@ export function buildCreateApi<Modules extends [Module<any>, ...Module<any>[]]>(
 
     const api = {
       injectEndpoints,
+      addTagTypes(...addTagTypes) {
+        for (const eT of addTagTypes) {
+          if (!optionsWithDefaults.tagTypes!.includes(eT as any)) {
+            ;(optionsWithDefaults.tagTypes as any[]).push(eT)
+          }
+        }
+        return api
+      },
+      enhanceEndpoint(endpointName, partialDefinition) {
+        if (typeof partialDefinition === 'function') {
+          ;(partialDefinition as any)(context.endpointDefinitions[endpointName])
+        } else {
+          Object.assign(
+            context.endpointDefinitions[endpointName] || {},
+            partialDefinition,
+          )
+        }
+        return api
+      },
       enhanceEndpoints({ addTagTypes, endpoints }) {
         if (addTagTypes) {
-          for (const eT of addTagTypes) {
-            if (!optionsWithDefaults.tagTypes!.includes(eT as any)) {
-              ;(optionsWithDefaults.tagTypes as any[]).push(eT)
-            }
-          }
+          api.addTagTypes(...addTagTypes)
         }
         if (endpoints) {
           for (const [endpointName, partialDefinition] of Object.entries(
             endpoints,
           )) {
-            if (typeof partialDefinition === 'function') {
-              partialDefinition(context.endpointDefinitions[endpointName])
-            } else {
-              Object.assign(
-                context.endpointDefinitions[endpointName] || {},
-                partialDefinition,
-              )
-            }
+            ;(api.enhanceEndpoint as any)(endpointName, partialDefinition)
           }
         }
         return api
@@ -381,6 +389,6 @@ export function buildCreateApi<Modules extends [Module<any>, ...Module<any>[]]>(
       return api as any
     }
 
-    return api.injectEndpoints({ endpoints: options.endpoints as any })
+    return api.injectEndpoints({ endpoints: options.endpoints as any }) as any
   }
 }
diff --git a/packages/toolkit/src/query/endpointDefinitions.ts b/packages/toolkit/src/query/endpointDefinitions.ts
index d0338e25bf..f82f418ba7 100644
--- a/packages/toolkit/src/query/endpointDefinitions.ts
+++ b/packages/toolkit/src/query/endpointDefinitions.ts
@@ -812,6 +812,70 @@ export type OverrideResultType<Definition, NewResultType> =
         >
       : never
 
+export type AddTagTypes<
+  Definitions extends EndpointDefinitions,
+  NewTagTypes extends string,
+> = {
+  [K in keyof Definitions]: Definitions[K] extends QueryDefinition<
+    infer QueryArg,
+    infer BaseQuery,
+    any,
+    infer ResultType,
+    infer ReducerPath
+  >
+    ? QueryDefinition<QueryArg, BaseQuery, NewTagTypes, ResultType, ReducerPath>
+    : Definitions[K] extends MutationDefinition<
+          infer QueryArg,
+          infer BaseQuery,
+          any,
+          infer ResultType,
+          infer ReducerPath
+        >
+      ? MutationDefinition<
+          QueryArg,
+          BaseQuery,
+          NewTagTypes,
+          ResultType,
+          ReducerPath
+        >
+      : never
+}
+
+export type EnhanceEndpoint<
+  Definition extends EndpointDefinition<any, any, any, any, any>,
+  NewQueryArg,
+  NewResultType,
+> =
+  Definition extends QueryDefinition<
+    any,
+    infer BaseQuery,
+    infer TagTypes,
+    any,
+    infer ReducerPath
+  >
+    ? QueryDefinition<
+        NewQueryArg,
+        BaseQuery,
+        TagTypes,
+        NewResultType,
+        ReducerPath
+      >
+    : Definition extends MutationDefinition<
+          any,
+          infer BaseQuery,
+          infer TagTypes,
+          any,
+          infer ReducerPath
+        >
+      ? MutationDefinition<
+          NewQueryArg,
+          BaseQuery,
+          TagTypes,
+          NewResultType,
+          ReducerPath
+        >
+      : never
+
 export type UpdateDefinitions<
   Definitions extends EndpointDefinitions,
   NewTagTypes extends string,
diff --git a/packages/toolkit/src/query/react/ApiProvider.tsx b/packages/toolkit/src/query/react/ApiProvider.tsx
index 2c42605a51..679d95146b 100644
--- a/packages/toolkit/src/query/react/ApiProvider.tsx
+++ b/packages/toolkit/src/query/react/ApiProvider.tsx
@@ -6,7 +6,7 @@ import React from 'react'
 import type { ReactReduxContextValue } from 'react-redux'
 import { Provider, ReactReduxContext } from 'react-redux'
 import { setupListeners } from '@reduxjs/toolkit/query'
-import type { Api } from '@reduxjs/toolkit/query'
+import type { ApiModules, CoreModule } from '@reduxjs/toolkit/query'
 
 /**
  * Can be used as a `Provider` if you **do not already have a Redux store**.
@@ -34,7 +34,7 @@ import type { Api } from '@reduxjs/toolkit/query'
  */
 export function ApiProvider(props: {
   children: any
-  api: Api<any, {}, any, any>
+  api: ApiModules<any, any, any, any>[CoreModule]
   setupListeners?: Parameters<typeof setupListeners>[1] | false
   context?: Context<ReactReduxContextValue | null>
 }) {
diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts
index 06b7596385..c946443890 100644
--- a/packages/toolkit/src/query/react/buildHooks.ts
+++ b/packages/toolkit/src/query/react/buildHooks.ts
@@ -9,6 +9,7 @@ import type {
   ApiContext,
   ApiEndpointMutation,
   ApiEndpointQuery,
+  ApiModules,
   CoreModule,
   EndpointDefinitions,
   MutationActionCreatorResult,
@@ -658,7 +659,7 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
   serializeQueryArgs,
   context,
 }: {
-  api: Api<any, Definitions, any, any, CoreModule>
+  api: ApiModules<any, Definitions, any, any>[CoreModule]
   moduleOptions: Required<ReactHooksModuleOptions>
   serializeQueryArgs: SerializeQueryArgs<any>
   context: ApiContext<Definitions>
diff --git a/packages/toolkit/src/query/tests/createApi.test-d.ts b/packages/toolkit/src/query/tests/createApi.test-d.ts
index b33ced1f6e..c066902914 100644
--- a/packages/toolkit/src/query/tests/createApi.test-d.ts
+++ b/packages/toolkit/src/query/tests/createApi.test-d.ts
@@ -2,13 +2,10 @@ import { setupApiStore } from '@internal/tests/utils/helpers'
 import type { SerializedError } from '@reduxjs/toolkit'
 import { configureStore } from '@reduxjs/toolkit'
 import type {
-  DefinitionsFromApi,
   FetchBaseQueryError,
   MutationDefinition,
-  OverrideResultType,
   QueryDefinition,
   TagDescription,
-  TagTypesFromApi,
 } from '@reduxjs/toolkit/query'
 import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
 
@@ -212,48 +209,20 @@ describe('type tests', () => {
           withoutTestLifecycles: true,
         })
 
-        api1.enhanceEndpoints({
-          endpoints: {
-            query1: {
-              // @ts-expect-error
-              providesTags: ['new'],
-            },
-            query2: {
-              // @ts-expect-error
-              providesTags: ['missing'],
-            },
-          },
-        })
+        // @ts-expect-error the location of the error varies depending on TS version, so this needs to be one line
+        // prettier-ignore
+        api1.enhanceEndpoint('query1', { providesTags: ['new'] }).enhanceEndpoint('query2', { providesTags: ['missing'] })
 
-        const enhanced = api1.enhanceEndpoints({
-          addTagTypes: ['new'],
-          endpoints: {
-            query1: {
-              providesTags: ['new'],
-            },
-            query2: {
-              // @ts-expect-error
-              providesTags: ['missing'],
-            },
-          },
-        })
+        const enhanced = api1
+          .addTagTypes('new')
+          .enhanceEndpoint('query1', { providesTags: ['new'] })
+
+        // @ts-expect-error
+        enhanced.enhanceEndpoint('query2', { providesTags: ['missing'] })
 
         storeRef.store.dispatch(api1.endpoints.query1.initiate('in1'))
 
         storeRef.store.dispatch(api1.endpoints.query2.initiate('in2'))
-
-        enhanced.enhanceEndpoints({
-          endpoints: {
-            query1: {
-              // returned `enhanced` api contains "new" entityType
-              providesTags: ['new'],
-            },
-            query2: {
-              // @ts-expect-error
-              providesTags: ['missing'],
-            },
-          },
-        })
       })
 
       test('modify', () => {
@@ -261,40 +230,38 @@ describe('type tests', () => {
           withoutTestLifecycles: true,
         })
 
-        api1.enhanceEndpoints({
-          endpoints: {
-            query1: {
-              query: (x) => {
-                expectTypeOf(x).toEqualTypeOf<'in1'>()
+        api1
+          .enhanceEndpoint('query1', {
+            query: (x) => {
+              expectTypeOf(x).toEqualTypeOf<'in1'>()
 
-                return 'modified1'
-              },
+              return 'modified1'
             },
-            query2(definition) {
-              definition.query = (x) => {
-                expectTypeOf(x).toEqualTypeOf<'in2'>()
+          })
+          .enhanceEndpoint('query2', (definition) => {
+            definition.query = (x) => {
+              expectTypeOf(x).toEqualTypeOf<'in2'>()
+
+              return 'modified2'
+            }
+          })
+          .enhanceEndpoint('mutation1', {
+            query: (x) => {
+              expectTypeOf(x).toEqualTypeOf<'in1'>()
 
-                return 'modified2'
-              }
+              return 'modified1'
             },
-            mutation1: {
-              query: (x) => {
-                expectTypeOf(x).toEqualTypeOf<'in1'>()
+          })
+          .enhanceEndpoint('mutation2', (definition) => {
+            definition.query = (x) => {
+              expectTypeOf(x).toEqualTypeOf<'in2'>()
 
-                return 'modified1'
-              },
-            },
-            mutation2(definition) {
-              definition.query = (x) => {
-                expectTypeOf(x).toEqualTypeOf<'in2'>()
+              return 'modified2'
+            }
+          })
 
-                return 'modified2'
-              }
-            },
-            // @ts-expect-error
-            nonExisting: {},
-          },
-        })
+        // @ts-expect-error
+        api1.enhanceEndpoint('nonexisting', {})
 
         storeRef.store.dispatch(api1.endpoints.query1.initiate('in1'))
         storeRef.store.dispatch(api1.endpoints.query2.initiate('in2'))
@@ -314,42 +281,34 @@ describe('type tests', () => {
 
         type Transformed = { value: string }
 
-        type Definitions = DefinitionsFromApi<typeof api1>
-
-        type TagTypes = TagTypesFromApi<typeof api1>
-
-        type Q1Definition = OverrideResultType<
-          Definitions['query1'],
-          Transformed
-        >
-
-        type M1Definition = OverrideResultType<
-          Definitions['mutation1'],
-          Transformed
-        >
+        const enhancedApi = baseApi
+          .enhanceEndpoint('query1', {
+            transformResponse: (a, b, c) => ({
+              value: 'transformed',
+            }),
+          })
+          .enhanceEndpoint('mutation1', {
+            transformResponse: (a, b, c) => ({
+              value: 'transformed',
+            }),
+          })
 
-        type UpdatedDefinitions = Omit<Definitions, 'query1' | 'mutation1'> & {
-          query1: Q1Definition
-          mutation1: M1Definition
-        }
+        // generics need to be provided manually if using callback enhancer
 
-        const enhancedApi = baseApi.enhanceEndpoints<
-          TagTypes,
-          UpdatedDefinitions
-        >({
-          endpoints: {
-            query1: {
-              transformResponse: (a, b, c) => ({
-                value: 'transformed',
-              }),
-            },
-            mutation1: {
-              transformResponse: (a, b, c) => ({
+        const enhancedApi2 = baseApi
+          .enhanceEndpoint<'query1', Transformed>('query1', (definition) => {
+            definition.transformResponse = (a, b, c) => ({
+              value: 'transformed',
+            })
+          })
+          .enhanceEndpoint<'mutation1', Transformed>(
+            'mutation1',
+            (definition) => {
+              definition.transformResponse = (a, b, c) => ({
                 value: 'transformed',
-              }),
+              })
             },
-          },
-        })
+          )
 
         const storeRef = setupApiStore(enhancedApi, undefined, {
           withoutTestLifecycles: true,
diff --git a/packages/toolkit/src/query/tests/createApi.test.ts b/packages/toolkit/src/query/tests/createApi.test.ts
index e1c3fad253..30ead1054c 100644
--- a/packages/toolkit/src/query/tests/createApi.test.ts
+++ b/packages/toolkit/src/query/tests/createApi.test.ts
@@ -406,32 +406,19 @@ describe('endpoint definition typings', () => {
       })
       // only type-test this part
       if (2 > 1) {
-        api.enhanceEndpoints({
-          endpoints: {
-            query1: {
-              // @ts-expect-error
-              providesTags: ['new'],
-            },
-            query2: {
-              // @ts-expect-error
-              providesTags: ['missing'],
-            },
-          },
+        // @ts-expect-error
+        api.enhanceEndpoint('query1', {
+          providesTags: ['new'],
+        })
+        // @ts-expect-error
+        api.enhanceEndpoint('query2', {
+          providesTags: ['missing'],
         })
       }
 
-      const enhanced = api.enhanceEndpoints({
-        addTagTypes: ['new'],
-        endpoints: {
-          query1: {
-            providesTags: ['new'],
-          },
-          query2: {
-            // @ts-expect-error
-            providesTags: ['missing'],
-          },
-        },
-      })
+      // @ts-expect-error the location of the error varies depending on TS version, so this needs to be one line
+      // prettier-ignore
+      const enhanced = api.addTagTypes('new').enhanceEndpoint('query1', { providesTags: ['new'] }).enhanceEndpoint('query2', { providesTags: ['missing'] })
 
       storeRef.store.dispatch(api.endpoints.query1.initiate('in1'))
       await delay(1)
@@ -445,17 +432,12 @@ describe('endpoint definition typings', () => {
 
       // only type-test this part
       if (2 > 1) {
-        enhanced.enhanceEndpoints({
-          endpoints: {
-            query1: {
-              // returned `enhanced` api contains "new" enitityType
-              providesTags: ['new'],
-            },
-            query2: {
-              // @ts-expect-error
-              providesTags: ['missing'],
-            },
-          },
+        enhanced.enhanceEndpoint('query1', {
+          providesTags: ['new'], // tag was added
+        })
+        // @ts-expect-error
+        enhanced.enhanceEndpoint('query2', {
+          providesTags: ['missing'],
         })
       }
     })
@@ -464,37 +446,32 @@ describe('endpoint definition typings', () => {
       const storeRef = setupApiStore(api, undefined, {
         withoutTestLifecycles: true,
       })
-      api.enhanceEndpoints({
-        endpoints: {
-          query1: {
-            query: (x) => {
-              return 'modified1'
-            },
-          },
-          query2(definition) {
-            definition.query = (x) => {
-              return 'modified2'
-            }
-          },
-          mutation1: {
-            query: (x) => {
-              return 'modified1'
-            },
+      const enhanced = api
+        .enhanceEndpoint('query1', {
+          query: (x) => {
+            return 'modified1'
           },
-          mutation2(definition) {
-            definition.query = (x) => {
-              return 'modified2'
-            }
+        })
+        .enhanceEndpoint('query2', function query2(definition) {
+          definition.query = (x) => {
+            return 'modified2'
+          }
+        })
+        .enhanceEndpoint('mutation1', {
+          query: (x) => {
+            return 'modified1'
           },
-          // @ts-expect-error
-          nonExisting: {},
-        },
-      })
+        })
+        .enhanceEndpoint('mutation2', function mutation2(definition) {
+          definition.query = (x) => {
+            return 'modified2'
+          }
+        })
 
-      storeRef.store.dispatch(api.endpoints.query1.initiate('in1'))
-      storeRef.store.dispatch(api.endpoints.query2.initiate('in2'))
-      storeRef.store.dispatch(api.endpoints.mutation1.initiate('in1'))
-      storeRef.store.dispatch(api.endpoints.mutation2.initiate('in2'))
+      storeRef.store.dispatch(enhanced.endpoints.query1.initiate('in1'))
+      storeRef.store.dispatch(enhanced.endpoints.query2.initiate('in2'))
+      storeRef.store.dispatch(enhanced.endpoints.mutation1.initiate('in1'))
+      storeRef.store.dispatch(enhanced.endpoints.mutation2.initiate('in2'))
 
       expect(baseQuery.mock.calls).toEqual([
         ['modified1', commonBaseQueryApi, undefined],
@@ -514,36 +491,23 @@ describe('endpoint definition typings', () => {
         }),
       })
 
-      type Transformed = { value: string }
-
-      type Definitions = DefinitionsFromApi<typeof api>
-      type TagTypes = TagTypesFromApi<typeof api>
-
-      type Q1Definition = OverrideResultType<Definitions['query1'], Transformed>
-      type M1Definition = OverrideResultType<
-        Definitions['mutation1'],
-        Transformed
-      >
-
-      type UpdatedDefitions = Omit<Definitions, 'query1' | 'mutation1'> & {
-        query1: Q1Definition
-        mutation1: M1Definition
+      const transformed = {
+        value: 'transformed',
       }
 
-      const enhancedApi = baseApi.enhanceEndpoints<TagTypes, UpdatedDefitions>({
-        endpoints: {
-          query1: {
-            transformResponse: (a, b, c) => ({
-              value: 'transformed',
-            }),
-          },
-          mutation1: {
-            transformResponse: (a, b, c) => ({
-              value: 'transformed',
-            }),
+      type Transformed = typeof transformed
+
+      const enhancedApi = baseApi
+        .enhanceEndpoint('query1', {
+          transformResponse: () => transformed,
+        })
+        // technically a cast, but works:tm:
+        .enhanceEndpoint<'mutation1', Transformed>(
+          'mutation1',
+          (definition) => {
+            definition.transformResponse = () => transformed
           },
-        },
-      })
+        )
 
       const storeRef = setupApiStore(enhancedApi, undefined, {
         withoutTestLifecycles: true,
@@ -552,14 +516,14 @@ describe('endpoint definition typings', () => {
       const queryResponse = await storeRef.store.dispatch(
         enhancedApi.endpoints.query1.initiate(),
       )
-      expect(queryResponse.data).toEqual({ value: 'transformed' })
+      expect(queryResponse.data).toEqual(transformed)
 
       const mutationResponse = await storeRef.store.dispatch(
         enhancedApi.endpoints.mutation1.initiate(),
       )
-      expect('data' in mutationResponse && mutationResponse.data).toEqual({
-        value: 'transformed',
-      })
+      expect('data' in mutationResponse && mutationResponse.data).toEqual(
+        transformed,
+      )
     })
   })
 })
diff --git a/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx b/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx
index 5ab0d8f215..f4a3961445 100644
--- a/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx
+++ b/packages/toolkit/src/query/tests/useMutation-fixedCacheKey.test.tsx
@@ -359,12 +359,8 @@ describe('fixedCacheKey', () => {
   })
 
   test('using fixedCacheKey should create a new cache entry', async () => {
-    api.enhanceEndpoints({
-      endpoints: {
-        send: {
-          onCacheEntryAdded: (arg) => onNewCacheEntry(arg),
-        },
-      },
+    api.enhanceEndpoint('send', {
+      onCacheEntryAdded: (arg) => onNewCacheEntry(arg),
     })
 
     render(<Component name="C1" fixedCacheKey={'testKey'} />, {
@@ -383,12 +379,8 @@ describe('fixedCacheKey', () => {
 
     expect(onNewCacheEntry).toHaveBeenCalledWith('C1')
 
-    api.enhanceEndpoints({
-      endpoints: {
-        send: {
-          onCacheEntryAdded: undefined,
-        },
-      },
+    api.enhanceEndpoint('send', {
+      onCacheEntryAdded: undefined,
     })
   })
 })
diff --git a/packages/toolkit/src/query/tests/utils.test.ts b/packages/toolkit/src/query/tests/utils.test.ts
index 859865c6d7..2adb7bfc20 100644
--- a/packages/toolkit/src/query/tests/utils.test.ts
+++ b/packages/toolkit/src/query/tests/utils.test.ts
@@ -4,6 +4,7 @@ import {
   isDocumentVisible,
   flatten,
   joinUrls,
+  promiseWithResolvers,
 } from '@internal/query/utils'
 
 afterAll(() => {
@@ -107,3 +108,30 @@ describe('flatten', () => {
     expect(flattenResult).toEqual([1, 2, 3, 4, [5, 6]])
   })
 })
+
+describe('promiseWithResolvers', () => {
+  test('provides promise along with lifecycle methods', async () => {
+    const stringPromise = promiseWithResolvers<string>()
+
+    stringPromise.resolve('foo')
+
+    if (2 < 1) {
+      // only type test this
+      // @ts-expect-error
+      stringPromise.resolve(0)
+    }
+
+    await expect(stringPromise.promise).resolves.toBe('foo')
+
+    const thrownPromise = promiseWithResolvers<void, string>()
+
+    thrownPromise.reject('an error')
+
+    if (2 < 1) {
+      // @ts-expect-error
+      thrownPromise.reject(0)
+    }
+
+    await expect(thrownPromise.promise).rejects.toThrow('an error')
+  })
+})
diff --git a/packages/toolkit/src/query/utils/index.ts b/packages/toolkit/src/query/utils/index.ts
index 46694a2c3f..31a2061c34 100644
--- a/packages/toolkit/src/query/utils/index.ts
+++ b/packages/toolkit/src/query/utils/index.ts
@@ -1,8 +1,10 @@
+export * from './capitalize'
+export * from './copyWithStructuralSharing'
+export * from './flatten'
 export * from './isAbsoluteUrl'
+export * from './isDocumentVisible'
+export * from './isNotNullish'
+export * from './isOnline'
 export * from './isValidUrl'
 export * from './joinUrls'
-export * from './flatten'
-export * from './capitalize'
-export * from './isOnline'
-export * from './isDocumentVisible'
-export * from './copyWithStructuralSharing'
+export * from './promiseWithResolvers'
diff --git a/packages/toolkit/src/query/utils/promiseWithResolvers.ts b/packages/toolkit/src/query/utils/promiseWithResolvers.ts
new file mode 100644
index 0000000000..eb8c926270
--- /dev/null
+++ b/packages/toolkit/src/query/utils/promiseWithResolvers.ts
@@ -0,0 +1,72 @@
+import { safeAssign } from '../tsHelpers'
+
+export interface PromiseConstructorWithKnownReason {
+  /**
+   * Creates a new Promise with a known rejection reason.
+   * @param executor A callback used to initialize the promise. This callback is passed two arguments:
+   * a resolve callback used to resolve the promise with a value or the result of another promise,
+   * and a reject callback used to reject the promise with a provided reason or error.
+   */
+  new <T, R>(
+    executor: (
+      resolve: (value: T | PromiseLike<T>) => void,
+      reject: (reason: R) => void,
+    ) => void,
+  ): PromiseWithKnownReason<T, R>
+}
+
+export interface PromiseWithKnownReason<T, R>
+  extends Omit<Promise<T>, 'then' | 'catch'> {
+  /**
+   * Attaches callbacks for the resolution and/or rejection of the Promise.
+   * @param onfulfilled The callback to execute when the Promise is resolved.
+   * @param onrejected The callback to execute when the Promise is rejected.
+   * @returns A Promise for the completion of which ever callback is executed.
+   */
+  then<TResult1 = T, TResult2 = never>(
+    onfulfilled?:
+      | ((value: T) => TResult1 | PromiseLike<TResult1>)
+      | undefined
+      | null,
+    onrejected?:
+      | ((reason: R) => TResult2 | PromiseLike<TResult2>)
+      | undefined
+      | null,
+  ): Promise<TResult1 | TResult2>
+
+  /**
+   * Attaches a callback for only the rejection of the Promise.
+   * @param onrejected The callback to execute when the Promise is rejected.
+   * @returns A Promise for the completion of the callback.
+   */
+  catch<TResult = never>(
+    onrejected?:
+      | ((reason: R) => TResult | PromiseLike<TResult>)
+      | undefined
+      | null,
+  ): Promise<T | TResult>
+}
+
+export const PromiseWithKnownReason =
+  Promise as PromiseConstructorWithKnownReason
+
+type PromiseExecutor<T, R> = ConstructorParameters<
+  typeof PromiseWithKnownReason<T, R>
+>[0]
+
+export type PromiseWithResolvers<T, R> = {
+  promise: PromiseWithKnownReason<T, R>
+  resolve: Parameters<PromiseExecutor<T, R>>[0]
+  reject: Parameters<PromiseExecutor<T, R>>[1]
+}
+
+export const promiseWithResolvers = <T, R = unknown>(): PromiseWithResolvers<
+  T,
+  R
+> => {
+  const result = {} as PromiseWithResolvers<T, R>
+  result.promise = new PromiseWithKnownReason<T, R>((resolve, reject) => {
+    safeAssign(result, { reject, resolve })
+  })
+  return result
+}