diff --git a/docs/api/createEntityAdapter.mdx b/docs/api/createEntityAdapter.mdx
index 7a60e41a79..1499661100 100644
--- a/docs/api/createEntityAdapter.mdx
+++ b/docs/api/createEntityAdapter.mdx
@@ -239,7 +239,7 @@ In other words, they accept a state that looks like `{ids: [], entities: {}}`, a
 
 These CRUD methods may be used in multiple ways:
 
-- They may be passed as case reducers directly to `createReducer` and `createSlice`.
+- They may be passed as case reducers directly to `createReducer` and `createSlice`. (also see the [`create.entityMethods`](./createSlice#createentitymethods-entitymethodscreator) slice creator which can assist with this)
 - They may be used as "mutating" helper methods when called manually, such as a separate hand-written call to `addOne()` inside of an existing case reducer, if the `state` argument is actually an Immer `Draft` value.
 - They may be used as immutable update methods when called manually, if the `state` argument is actually a plain JS object or array.
 
diff --git a/docs/usage/custom-slice-creators.mdx b/docs/usage/custom-slice-creators.mdx
index 6cfbbdd0b1..bf71565083 100644
--- a/docs/usage/custom-slice-creators.mdx
+++ b/docs/usage/custom-slice-creators.mdx
@@ -324,6 +324,105 @@ reducers: (create) => {
 
 :::
 
+##### `create.entityMethods` (`entityMethodsCreator`)
+
+Creates a set of reducers for managing a normalized entity state, based on a provided [adapter](./createEntityAdapter).
+
+```ts
+import {
+  createEntityAdapter,
+  buildCreateSlice,
+  entityMethodsCreator,
+} from '@reduxjs/toolkit'
+
+const createAppSlice = buildCreateSlice({
+  creators: { entityMethods: entityMethodsCreator },
+})
+
+interface Post {
+  id: string
+  text: string
+}
+
+const postsAdapter = createEntityAdapter<Post>()
+
+const postsSlice = createAppSlice({
+  name: 'posts',
+  initialState: postsAdapter.getInitialState(),
+  reducers: (create) => ({
+    ...create.entityMethods(postsAdapter),
+  }),
+})
+
+export const { setOne, upsertMany, removeAll, ...etc } = postsSlice.actions
+```
+
+:::caution
+
+Because this creator returns an object of multiple reducer definitions, it should be spread into the final object returned by the `reducers` callback.
+
+:::
+
+**Parameters**
+
+- **adapter** The [adapter](../api/createEntityAdapter) to use.
+- **config** The configuration object. (optional)
+
+The configuration object can contain some of the following options:
+
+**`selectEntityState`**
+
+A selector to retrieve the entity state from the slice state. Defaults to `state => state`, but should be provided if the entity state is nested.
+
+```ts no-transpile
+const postsSlice = createAppSlice({
+  name: 'posts',
+  initialState: { posts: postsAdapter.getInitialState() },
+  reducers: (create) => ({
+    ...create.entityMethods(postsAdapter, {
+      selectEntityState: (state) => state.posts,
+    }),
+  }),
+})
+```
+
+**`name`, `pluralName`**
+
+It's often desirable to modify the reducer names to be specific to the data type being used. These options allow you to do that simply.
+
+```ts no-transpile
+const postsSlice = createAppSlice({
+  name: 'posts',
+  initialState: postsAdapter.getInitialState(),
+  reducers: (create) => ({
+    ...create.entityMethods(postsAdapter, {
+      name: 'post',
+    }),
+  }),
+})
+
+const { addOnePost, upsertManyPosts, removeAllPosts, ...etc } =
+  postsSlice.actions
+```
+
+`pluralName` defaults to `name + 's'`, but can be provided if this isn't desired.
+
+```ts no-transpile
+const gooseSlice = createAppSlice({
+  name: 'geese',
+  initialState: gooseAdapter.getInitialState(),
+  reducers: (create) => ({
+    ...create.entityMethods(gooseAdapter, {
+      name: 'goose',
+      pluralName: 'geese',
+    }),
+  }),
+})
+
+const { addOneGoose, upsertManyGeese, removeAllGeese, ...etc } =
+  gooseSlice.actions
+```
+
 ## Writing your own creators
 
 In version v2.3.0, we introduced a system for including your own creators.
@@ -338,7 +437,7 @@ For example, the `create.preparedReducer` creator uses a definition that looks l
 
 The callback form of `reducers` should return an object of reducer definitions, by calling creators and nesting the result of each under a key.
 
-```js no-transpile
+```js
 reducers: (create) => ({
   addTodo: create.preparedReducer(
     (todo) => ({ payload: { id: nanoid(), ...todo } }),
diff --git a/packages/toolkit/src/asyncThunkCreator.ts b/packages/toolkit/src/asyncThunkCreator.ts
index a2a974a1bf..19fb0380ac 100644
--- a/packages/toolkit/src/asyncThunkCreator.ts
+++ b/packages/toolkit/src/asyncThunkCreator.ts
@@ -15,37 +15,6 @@ import type {
 import { ReducerType } from './createSlice'
 import type { Id } from './tsHelpers'
 
-export type AsyncThunkCreatorExposes<
-  State,
-  CaseReducers extends CreatorCaseReducers<State>,
-> = {
-  actions: {
-    [ReducerName in keyof CaseReducers]: CaseReducers[ReducerName] extends AsyncThunkSliceReducerDefinition<
-      State,
-      infer ThunkArg,
-      infer Returned,
-      infer ThunkApiConfig
-    >
-      ? AsyncThunk<Returned, ThunkArg, ThunkApiConfig>
-      : never
-  }
-  caseReducers: {
-    [ReducerName in keyof CaseReducers]: CaseReducers[ReducerName] extends AsyncThunkSliceReducerDefinition<
-      State,
-      any,
-      any,
-      any
-    >
-      ? Id<
-          Pick<
-            Required<CaseReducers[ReducerName]>,
-            'fulfilled' | 'rejected' | 'pending' | 'settled'
-          >
-        >
-      : never
-  }
-}
-
 export type AsyncThunkSliceReducerConfig<
   State,
   ThunkArg extends any,
@@ -145,6 +114,37 @@ export interface AsyncThunkCreator<
   >
 }
 
+export type AsyncThunkCreatorExposes<
+  State,
+  CaseReducers extends CreatorCaseReducers<State>,
+> = {
+  actions: {
+    [ReducerName in keyof CaseReducers]: CaseReducers[ReducerName] extends AsyncThunkSliceReducerDefinition<
+      State,
+      infer ThunkArg,
+      infer Returned,
+      infer ThunkApiConfig
+    >
+      ? AsyncThunk<Returned, ThunkArg, ThunkApiConfig>
+      : never
+  }
+  caseReducers: {
+    [ReducerName in keyof CaseReducers]: CaseReducers[ReducerName] extends AsyncThunkSliceReducerDefinition<
+      State,
+      any,
+      any,
+      any
+    >
+      ? Id<
+          Pick<
+            Required<CaseReducers[ReducerName]>,
+            'fulfilled' | 'rejected' | 'pending' | 'settled'
+          >
+        >
+      : never
+  }
+}
+
 export const asyncThunkCreator: ReducerCreator<ReducerType.asyncThunk> = {
   type: ReducerType.asyncThunk,
   create: /* @__PURE__ */ (() => {
diff --git a/packages/toolkit/src/createSlice.ts b/packages/toolkit/src/createSlice.ts
index ffe186835e..8b8000ab4d 100644
--- a/packages/toolkit/src/createSlice.ts
+++ b/packages/toolkit/src/createSlice.ts
@@ -20,6 +20,7 @@ import type {
   ReducerWithInitialState,
 } from './createReducer'
 import { createReducer, makeGetInitialState } from './createReducer'
+import type { EntityMethodsCreator } from './entities/slice_creator'
 import type { ActionReducerMapBuilder, TypedActionCreator } from './mapBuilders'
 import { executeReducerBuilderCallback } from './mapBuilders'
 import type {
@@ -36,6 +37,7 @@ export enum ReducerType {
   reducer = 'reducer',
   reducerWithPrepare = 'reducerWithPrepare',
   asyncThunk = 'asyncThunk',
+  entityMethods = 'entityMethods',
 }
 
 export type RegisteredReducerType = keyof SliceReducerCreators<
@@ -146,6 +148,7 @@ export interface SliceReducerCreators<
     AsyncThunkCreator<State>,
     AsyncThunkCreatorExposes<State, CaseReducers>
   >
+  [ReducerType.entityMethods]: ReducerCreatorEntry<EntityMethodsCreator<State>>
 }
 
 export type ReducerCreators<
diff --git a/packages/toolkit/src/entities/index.ts b/packages/toolkit/src/entities/index.ts
deleted file mode 100644
index e258527474..0000000000
--- a/packages/toolkit/src/entities/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export { createEntityAdapter } from './create_adapter'
-export type {
-  EntityState,
-  EntityAdapter,
-  Update,
-  IdSelector,
-  Comparer,
-} from './models'
diff --git a/packages/toolkit/src/entities/models.ts b/packages/toolkit/src/entities/models.ts
index 072b8a8894..2b20b84826 100644
--- a/packages/toolkit/src/entities/models.ts
+++ b/packages/toolkit/src/entities/models.ts
@@ -1,8 +1,10 @@
+import type { UncheckedIndexedAccess } from '../uncheckedindexed'
 import type { Draft } from 'immer'
 import type { PayloadAction } from '../createAction'
-import type { CastAny, Id } from '../tsHelpers'
-import type { UncheckedIndexedAccess } from '../uncheckedindexed.js'
 import type { GetSelectorsOptions } from './state_selectors'
+import type { CastAny, Id } from '../tsHelpers'
+import type { CaseReducerDefinition } from '../createSlice'
+import type { CaseReducer } from '../createReducer'
 
 /**
  * @public
@@ -158,12 +160,53 @@ export interface EntityStateAdapter<T, Id extends EntityId> {
 /**
  * @public
  */
-export interface EntitySelectors<T, V, IdType extends EntityId> {
-  selectIds: (state: V) => IdType[]
-  selectEntities: (state: V) => Record<IdType, T>
-  selectAll: (state: V) => T[]
-  selectTotal: (state: V) => number
-  selectById: (state: V, id: IdType) => Id<UncheckedIndexedAccess<T>>
+export type EntitySelectors<
+  T,
+  V,
+  IdType extends EntityId,
+  Single extends string = '',
+  Plural extends string = DefaultPlural<Single>,
+> = Id<
+  {
+    [K in `select${Capitalize<Single>}Ids`]: (state: V) => IdType[]
+  } & {
+    [K in `select${Capitalize<Single>}Entities`]: (
+      state: V,
+    ) => Record<IdType, T>
+  } & {
+    [K in `selectAll${Capitalize<Plural>}`]: (state: V) => T[]
+  } & {
+    [K in `selectTotal${Capitalize<Plural>}`]: (state: V) => number
+  } & {
+    [K in `select${Capitalize<Single>}ById`]: (
+      state: V,
+      id: IdType,
+    ) => Id<UncheckedIndexedAccess<T>>
+  }
+>
+
+export type DefaultPlural<Single extends string> = Single extends ''
+  ? ''
+  : `${Single}s`
+
+export type EntityReducers<
+  T,
+  Id extends EntityId,
+  State = EntityState<T, Id>,
+  Single extends string = '',
+  Plural extends string = DefaultPlural<Single>,
+> = {
+  [K in keyof EntityStateAdapter<
+    T,
+    Id
+  > as `${K}${Capitalize<K extends `${string}One` ? Single : Plural>}`]: EntityStateAdapter<
+    T,
+    Id
+  >[K] extends (state: any) => any
+    ? CaseReducerDefinition<State, PayloadAction>
+    : EntityStateAdapter<T, Id>[K] extends CaseReducer<any, infer A>
+      ? CaseReducerDefinition<State, A>
+      : never
 }
 
 /**
@@ -187,12 +230,19 @@ export interface EntityAdapter<T, Id extends EntityId>
   extends EntityStateAdapter<T, Id>,
     EntityStateFactory<T, Id>,
     Required<EntityAdapterOptions<T, Id>> {
-  getSelectors(
+  getSelectors<
+    Single extends string = '',
+    Plural extends string = DefaultPlural<Single>,
+  >(
     selectState?: undefined,
-    options?: GetSelectorsOptions,
-  ): EntitySelectors<T, EntityState<T, Id>, Id>
-  getSelectors<V>(
+    options?: GetSelectorsOptions<Single, Plural>,
+  ): EntitySelectors<T, EntityState<T, Id>, Id, Single, Plural>
+  getSelectors<
+    V,
+    Single extends string = '',
+    Plural extends string = DefaultPlural<Single>,
+  >(
     selectState: (state: V) => EntityState<T, Id>,
-    options?: GetSelectorsOptions,
-  ): EntitySelectors<T, V, Id>
+    options?: GetSelectorsOptions<Single, Plural>,
+  ): EntitySelectors<T, V, Id, Single, Plural>
 }
diff --git a/packages/toolkit/src/entities/slice_creator.ts b/packages/toolkit/src/entities/slice_creator.ts
new file mode 100644
index 0000000000..49f7a0a8a0
--- /dev/null
+++ b/packages/toolkit/src/entities/slice_creator.ts
@@ -0,0 +1,128 @@
+import type {
+  CaseReducerDefinition,
+  PayloadAction,
+  ReducerCreator,
+} from '@reduxjs/toolkit'
+import { reducerCreator, ReducerType } from '../createSlice'
+import type { WithRequiredProp } from '../tsHelpers'
+import type {
+  EntityAdapter,
+  EntityId,
+  EntityState,
+  DefaultPlural,
+  EntityReducers,
+} from './models'
+import { capitalize } from './utils'
+
+export interface EntityMethodsCreatorConfig<
+  T,
+  Id extends EntityId,
+  State,
+  Single extends string,
+  Plural extends string,
+> {
+  selectEntityState?: (state: State) => EntityState<T, Id>
+  name?: Single
+  pluralName?: Plural
+}
+
+export type EntityMethodsCreator<State> =
+  State extends EntityState<infer T, infer Id>
+    ? {
+        <
+          T,
+          Id extends EntityId,
+          Single extends string = '',
+          Plural extends string = DefaultPlural<Single>,
+        >(
+          adapter: EntityAdapter<T, Id>,
+          config: WithRequiredProp<
+            EntityMethodsCreatorConfig<T, Id, State, Single, Plural>,
+            'selectEntityState'
+          >,
+        ): EntityReducers<T, Id, State, Single, Plural>
+        <
+          Single extends string = '',
+          Plural extends string = DefaultPlural<Single>,
+        >(
+          adapter: EntityAdapter<T, Id>,
+          config?: Omit<
+            EntityMethodsCreatorConfig<T, Id, State, Single, Plural>,
+            'selectEntityState'
+          >,
+        ): EntityReducers<T, Id, State, Single, Plural>
+      }
+    : <
+        T,
+        Id extends EntityId,
+        Single extends string = '',
+        Plural extends string = DefaultPlural<Single>,
+      >(
+        adapter: EntityAdapter<T, Id>,
+        config: WithRequiredProp<
+          EntityMethodsCreatorConfig<T, Id, State, Single, Plural>,
+          'selectEntityState'
+        >,
+      ) => EntityReducers<T, Id, State, Single, Plural>
+
+const makeWrappedReducerCreator =
+  <T, Id extends EntityId, State>(
+    selectEntityState: (state: State) => EntityState<T, Id>,
+  ) =>
+  <Payload>(
+    mutator: (
+      state: EntityState<T, Id>,
+      action: PayloadAction<Payload>,
+    ) => void,
+  ): CaseReducerDefinition<State, PayloadAction<Payload>> =>
+    reducerCreator.create<Payload>((state: State, action) => {
+      mutator(selectEntityState(state), action)
+    })
+
+export function createEntityMethods<
+  T,
+  Id extends EntityId,
+  State = EntityState<T, Id>,
+  Single extends string = '',
+  Plural extends string = DefaultPlural<Single>,
+>(
+  adapter: EntityAdapter<T, Id>,
+  {
+    selectEntityState = (state) => state as unknown as EntityState<T, Id>,
+    name: nameParam = '' as Single,
+    pluralName: pluralParam = (nameParam && `${nameParam}s`) as Plural,
+  }: EntityMethodsCreatorConfig<T, Id, State, Single, Plural> = {},
+): EntityReducers<T, Id, State, Single, Plural> {
+  // template literal computed keys don't keep their type if there's an unresolved generic
+  // so we cast to some intermediate type to at least check we're using the right variables in the right places
+
+  const name = nameParam as 's'
+  const pluralName = pluralParam as 'p'
+  const reducer = makeWrappedReducerCreator(selectEntityState)
+  const reducers: EntityReducers<T, Id, State, 's', 'p'> = {
+    [`addOne${capitalize(name)}` as const]: reducer(adapter.addOne),
+    [`addMany${capitalize(pluralName)}` as const]: reducer(adapter.addMany),
+    [`setOne${capitalize(name)}` as const]: reducer(adapter.setOne),
+    [`setMany${capitalize(pluralName)}` as const]: reducer(adapter.setMany),
+    [`setAll${capitalize(pluralName)}` as const]: reducer(adapter.setAll),
+    [`removeOne${capitalize(name)}` as const]: reducer(adapter.removeOne),
+    [`removeMany${capitalize(pluralName)}` as const]: reducer(
+      adapter.removeMany,
+    ),
+    [`removeAll${capitalize(pluralName)}` as const]: reducer(adapter.removeAll),
+    [`upsertOne${capitalize(name)}` as const]: reducer(adapter.upsertOne),
+    [`upsertMany${capitalize(pluralName)}` as const]: reducer(
+      adapter.upsertMany,
+    ),
+    [`updateOne${capitalize(name)}` as const]: reducer(adapter.updateOne),
+    [`updateMany${capitalize(pluralName)}` as const]: reducer(
+      adapter.updateMany,
+    ),
+  }
+  return reducers as any
+}
+
+export const entityMethodsCreator: ReducerCreator<ReducerType.entityMethods> = {
+  type: ReducerType.entityMethods,
+  create: createEntityMethods,
+}
diff --git a/packages/toolkit/src/entities/state_selectors.ts b/packages/toolkit/src/entities/state_selectors.ts
index 2893c99405..7d06613dcf 100644
--- a/packages/toolkit/src/entities/state_selectors.ts
+++ b/packages/toolkit/src/entities/state_selectors.ts
@@ -1,6 +1,12 @@
 import type { CreateSelectorFunction, Selector } from 'reselect'
 import { createDraftSafeSelector } from '../createDraftSafeSelector'
-import type { EntityId, EntitySelectors, EntityState } from './models'
+import type {
+  EntityState,
+  EntitySelectors,
+  EntityId,
+  DefaultPlural,
+} from './models'
+import { capitalize } from './utils'
 
 type AnyFunction = (...args: any) => any
 type AnyCreateSelectorFunction = CreateSelectorFunction<
@@ -8,25 +14,43 @@ type AnyCreateSelectorFunction = CreateSelectorFunction<
   <F extends AnyFunction>(f: F) => F
 >
 
-export type GetSelectorsOptions = {
+export type GetSelectorsOptions<
+  Single extends string = '',
+  Plural extends string = DefaultPlural<''>,
+> = {
   createSelector?: AnyCreateSelectorFunction
+  name?: Single
+  pluralName?: Plural
 }
 
 export function createSelectorsFactory<T, Id extends EntityId>() {
-  function getSelectors(
+  function getSelectors<
+    Single extends string = '',
+    Plural extends string = DefaultPlural<Single>,
+  >(
     selectState?: undefined,
-    options?: GetSelectorsOptions,
-  ): EntitySelectors<T, EntityState<T, Id>, Id>
-  function getSelectors<V>(
+    options?: GetSelectorsOptions<Single, Plural>,
+  ): EntitySelectors<T, EntityState<T, Id>, Id, Single, Plural>
+  function getSelectors<
+    V,
+    Single extends string = '',
+    Plural extends string = DefaultPlural<Single>,
+  >(
     selectState: (state: V) => EntityState<T, Id>,
-    options?: GetSelectorsOptions,
-  ): EntitySelectors<T, V, Id>
-  function getSelectors<V>(
+    options?: GetSelectorsOptions<Single, Plural>,
+  ): EntitySelectors<T, V, Id, Single, Plural>
+  function getSelectors<
+    V,
+    Single extends string = '',
+    Plural extends string = DefaultPlural<Single>,
+  >(
     selectState?: (state: V) => EntityState<T, Id>,
-    options: GetSelectorsOptions = {},
-  ): EntitySelectors<T, any, Id> {
+    options: GetSelectorsOptions<Single, Plural> = {},
+  ): EntitySelectors<T, any, Id, Single, Plural> {
     const {
       createSelector = createDraftSafeSelector as AnyCreateSelectorFunction,
+      name = '',
+      pluralName = name && `${name}s`,
     } = options
 
     const selectIds = (state: EntityState<T, Id>) => state.ids
@@ -45,14 +69,25 @@ export function createSelectorsFactory<T, Id extends EntityId>() {
 
     const selectTotal = createSelector(selectIds, (ids) => ids.length)
 
+    // template literal computed keys don't keep their type if there's an unresolved generic
+    // so we cast to some intermediate type to at least check we're using the right variables in the right places
+
+    const single = name as 's'
+    const plural = pluralName as 'p'
+
     if (!selectState) {
-      return {
-        selectIds,
-        selectEntities,
-        selectAll,
-        selectTotal,
-        selectById: createSelector(selectEntities, selectId, selectById),
+      const selectors: EntitySelectors<T, any, Id, 's', 'p'> = {
+        [`select${capitalize(single)}Ids` as const]: selectIds,
+        [`select${capitalize(single)}Entities` as const]: selectEntities,
+        [`selectAll${capitalize(plural)}` as const]: selectAll,
+        [`selectTotal${capitalize(plural)}` as const]: selectTotal,
+        [`select${capitalize(single)}ById` as const]: createSelector(
+          selectEntities,
+          selectId,
+          selectById,
+        ),
       }
+      return selectors as any
     }
 
     const selectGlobalizedEntities = createSelector(
@@ -60,17 +95,28 @@ export function createSelectorsFactory<T, Id extends EntityId>() {
       selectEntities,
     )
 
-    return {
-      selectIds: createSelector(selectState, selectIds),
-      selectEntities: selectGlobalizedEntities,
-      selectAll: createSelector(selectState, selectAll),
-      selectTotal: createSelector(selectState, selectTotal),
-      selectById: createSelector(
+    const selectors: EntitySelectors<T, any, Id, 's', 'p'> = {
+      [`select${capitalize(single)}Ids` as const]: createSelector(
+        selectState,
+        selectIds,
+      ),
+      [`select${capitalize(single)}Entities` as const]:
+        selectGlobalizedEntities,
+      [`selectAll${capitalize(plural)}` as const]: createSelector(
+        selectState,
+        selectAll,
+      ),
+      [`selectTotal${capitalize(plural)}` as const]: createSelector(
+        selectState,
+        selectTotal,
+      ),
+      [`select${capitalize(single)}ById` as const]: createSelector(
         selectGlobalizedEntities,
         selectId,
         selectById,
       ),
     }
+    return selectors as any
   }
 
   return { getSelectors }
diff --git a/packages/toolkit/src/entities/tests/entity_slice_enhancer.test-d.ts b/packages/toolkit/src/entities/tests/entity_slice_enhancer.test-d.ts
new file mode 100644
index 0000000000..29eca94da9
--- /dev/null
+++ b/packages/toolkit/src/entities/tests/entity_slice_enhancer.test-d.ts
@@ -0,0 +1,74 @@
+import type { PayloadActionCreator } from '../../createAction'
+import {
+  buildCreateSlice,
+  createEntityAdapter,
+  entityMethodsCreator,
+  createEntityMethods,
+} from '@reduxjs/toolkit'
+import type { BookModel } from './fixtures/book'
+
+describe('entity slice creator', () => {
+  const createAppSlice = buildCreateSlice({
+    creators: { entityMethods: entityMethodsCreator },
+  })
+  it('should require selectEntityState if state is not compatible', () => {
+    const bookAdapter = createEntityAdapter<BookModel>()
+    const bookSlice = createAppSlice({
+      name: 'books',
+      initialState: { data: bookAdapter.getInitialState() },
+      reducers: (create) => ({
+        // @ts-expect-error
+        ...create.entityMethods(bookAdapter),
+        // @ts-expect-error
+        ...create.entityMethods(bookAdapter, {}),
+        ...create.entityMethods(bookAdapter, {
+          selectEntityState: (state) => state.data,
+        }),
+      }),
+    })
+    expectTypeOf(bookSlice.actions.addOne).toEqualTypeOf<
+      PayloadActionCreator<BookModel, 'books/addOne'>
+    >()
+  })
+  it('exports createEntityMethods which can be used in object form', () => {
+    const bookAdapter = createEntityAdapter<BookModel>()
+
+    const initialState = { data: bookAdapter.getInitialState() }
+
+    const bookSlice = createAppSlice({
+      name: 'books',
+      initialState: { data: bookAdapter.getInitialState() },
+      // @ts-expect-error
+      reducers: {
+        ...createEntityMethods(bookAdapter),
+      },
+    })
+
+    const bookSlice2 = createAppSlice({
+      name: 'books',
+      initialState,
+      reducers: {
+        ...entityMethodsCreator.create(bookAdapter, {
+          // cannot be inferred, needs annotation
+          selectEntityState: (state: typeof initialState) => state.data,
+        }),
+      },
+    })
+
+    expectTypeOf(bookSlice2.actions.addOne).toEqualTypeOf<
+      PayloadActionCreator<BookModel, 'books/addOne'>
+    >()
+
+    const bookSlice3 = createAppSlice({
+      name: 'books',
+      initialState: bookAdapter.getInitialState(),
+      reducers: {
+        ...createEntityMethods(bookAdapter),
+      },
+    })
+
+    expectTypeOf(bookSlice3.actions.addOne).toEqualTypeOf<
+      PayloadActionCreator<BookModel, 'books/addOne'>
+    >()
+  })
+})
diff --git a/packages/toolkit/src/entities/tests/entity_slice_enhancer.test.ts b/packages/toolkit/src/entities/tests/entity_slice_enhancer.test.ts
index 8694762af9..af5cab2638 100644
--- a/packages/toolkit/src/entities/tests/entity_slice_enhancer.test.ts
+++ b/packages/toolkit/src/entities/tests/entity_slice_enhancer.test.ts
@@ -1,54 +1,152 @@
-import { createEntityAdapter, createSlice } from '../..'
-import type { PayloadAction, SliceCaseReducers, UnknownAction } from '../..'
-import type { EntityId, IdSelector } from '../models'
-import type { BookModel } from './fixtures/book'
-
-describe('Entity Slice Enhancer', () => {
-  let slice: ReturnType<typeof entitySliceEnhancer<BookModel, string>>
-
-  beforeEach(() => {
-    const indieSlice = entitySliceEnhancer({
-      name: 'book',
-      selectId: (book: BookModel) => book.id,
-    })
-    slice = indieSlice
-  })
-
-  it('exposes oneAdded', () => {
-    const book = {
-      id: '0',
-      title: 'Der Steppenwolf',
-      author: 'Herman Hesse',
-    }
-    const action = slice.actions.oneAdded(book)
-    const oneAdded = slice.reducer(undefined, action as UnknownAction)
-    expect(oneAdded.entities['0']).toBe(book)
-  })
-})
-
-interface EntitySliceArgs<T, Id extends EntityId> {
-  name: string
-  selectId: IdSelector<T, Id>
-  modelReducer?: SliceCaseReducers<T>
-}
-
-function entitySliceEnhancer<T, Id extends EntityId>({
-  name,
-  selectId,
-  modelReducer,
-}: EntitySliceArgs<T, Id>) {
-  const modelAdapter = createEntityAdapter({
-    selectId,
-  })
-
-  return createSlice({
-    name,
-    initialState: modelAdapter.getInitialState(),
-    reducers: {
-      oneAdded(state, action: PayloadAction<T>) {
-        modelAdapter.addOne(state, action.payload)
-      },
-      ...modelReducer,
-    },
-  })
-}
+import {
+  buildCreateSlice,
+  createEntityAdapter,
+  createSlice,
+  entityMethodsCreator,
+  createEntityMethods,
+} from '@reduxjs/toolkit'
+import type {
+  PayloadAction,
+  SliceCaseReducers,
+  ValidateSliceCaseReducers,
+} from '../..'
+import type { EntityId, EntityState, IdSelector } from '../models'
+import { AClockworkOrange, type BookModel } from './fixtures/book'
+
+describe('Entity Slice Enhancer', () => {
+  let slice: ReturnType<typeof entitySliceEnhancer<BookModel, string>>
+
+  beforeEach(() => {
+    slice = entitySliceEnhancer({
+      name: 'book',
+      selectId: (book: BookModel) => book.id,
+    })
+  })
+
+  it('exposes oneAdded', () => {
+    const action = slice.actions.oneAdded(AClockworkOrange)
+    const oneAdded = slice.reducer(undefined, action)
+    expect(oneAdded.entities[AClockworkOrange.id]).toBe(AClockworkOrange)
+  })
+})
+
+interface EntitySliceArgs<
+  T,
+  Id extends EntityId,
+  CaseReducers extends SliceCaseReducers<EntityState<T, Id>>,
+> {
+  name: string
+  selectId: IdSelector<T, Id>
+  modelReducer?: ValidateSliceCaseReducers<EntityState<T, Id>, CaseReducers>
+}
+
+function entitySliceEnhancer<
+  T,
+  Id extends EntityId,
+  CaseReducers extends SliceCaseReducers<EntityState<T, Id>> = {},
+>({ name, selectId, modelReducer }: EntitySliceArgs<T, Id, CaseReducers>) {
+  const modelAdapter = createEntityAdapter({
+    selectId,
+  })
+
+  return createSlice({
+    name,
+    initialState: modelAdapter.getInitialState(),
+    reducers: {
+      oneAdded(state, action: PayloadAction<T>) {
+        modelAdapter.addOne(state, action.payload)
+      },
+      ...modelReducer,
+    },
+  })
+}
+
+describe('entity slice creator', () => {
+  const createAppSlice = buildCreateSlice({
+    creators: { entityMethods: entityMethodsCreator },
+  })
+
+  const bookAdapter = createEntityAdapter<BookModel>()
+
+  const bookSlice = createAppSlice({
+    name: 'book',
+    initialState: bookAdapter.getInitialState({
+      nested: bookAdapter.getInitialState(),
+    }),
+    reducers: (create) => ({
+      ...create.entityMethods(bookAdapter, {
+        name: 'book',
+      }),
+      ...create.entityMethods(bookAdapter, {
+        selectEntityState: (state) => state.nested,
+        name: 'nestedBook',
+        pluralName: 'nestedBookies',
+      }),
+    }),
+  })
+
+  it('should generate correct actions', () => {
+    expect(bookSlice.actions.addOneBook).toBeTypeOf('function')
+    expect(bookSlice.actions.addOneNestedBook).toBeTypeOf('function')
+    expect(bookSlice.actions.addManyBooks).toBeTypeOf('function')
+    expect(bookSlice.actions.addManyNestedBookies).toBeTypeOf('function')
+  })
+  it('should handle actions', () => {
+    const withBook = bookSlice.reducer(
+      undefined,
+      bookSlice.actions.addOneBook(AClockworkOrange),
+    )
+    expect(
+      bookAdapter.getSelectors().selectById(withBook, AClockworkOrange.id),
+    ).toBe(AClockworkOrange)
+
+    const withNestedBook = bookSlice.reducer(
+      withBook,
+      bookSlice.actions.addOneNestedBook(AClockworkOrange),
+    )
+    expect(
+      bookAdapter
+        .getSelectors(
+          (state: ReturnType<typeof bookSlice.reducer>) => state.nested,
+        )
+        .selectById(withNestedBook, AClockworkOrange.id),
+    ).toBe(AClockworkOrange)
+  })
+  it('should be able to be called without this context', () => {
+    const bookSlice = createAppSlice({
+      name: 'book',
+      initialState: bookAdapter.getInitialState(),
+      reducers: ({ entityMethods }) => ({
+        ...entityMethods(bookAdapter),
+      }),
+    })
+    expect(bookSlice.actions.addOne).toBeTypeOf('function')
+  })
+  it('can be called with object syntax', () => {
+    const bookSlice = createAppSlice({
+      name: 'book',
+      initialState: bookAdapter.getInitialState(),
+      reducers: {
+        ...createEntityMethods(bookAdapter, {
+          name: 'book',
+        }),
+      },
+    })
+    expect(bookSlice.actions.addOneBook).toBeTypeOf('function')
+
+    const initialState = { nested: bookAdapter.getInitialState() }
+    const nestedBookSlice = createAppSlice({
+      name: 'book',
+      initialState,
+      reducers: {
+        ...createEntityMethods(bookAdapter, {
+          // state can't be inferred, so needs to be annotated
+          selectEntityState: (state: typeof initialState) => state.nested,
+          name: 'nestedBook',
+          pluralName: 'nestedBookies',
+        }),
+      },
+    })
+    expect(nestedBookSlice.actions.addOneNestedBook).toBeTypeOf('function')
+  })
+})
diff --git a/packages/toolkit/src/entities/tests/entity_state.test.ts b/packages/toolkit/src/entities/tests/entity_state.test.ts
index 999ee502b9..b2473f1124 100644
--- a/packages/toolkit/src/entities/tests/entity_state.test.ts
+++ b/packages/toolkit/src/entities/tests/entity_state.test.ts
@@ -1,5 +1,5 @@
-import type { EntityAdapter } from '../index'
-import { createEntityAdapter } from '../index'
+import type { EntityAdapter } from '../models'
+import { createEntityAdapter } from '../create_adapter'
 import type { PayloadAction } from '../../createAction'
 import { createAction } from '../../createAction'
 import { createSlice } from '../../createSlice'
diff --git a/packages/toolkit/src/entities/tests/state_adapter.test.ts b/packages/toolkit/src/entities/tests/state_adapter.test.ts
index a05b715ff9..f691639b23 100644
--- a/packages/toolkit/src/entities/tests/state_adapter.test.ts
+++ b/packages/toolkit/src/entities/tests/state_adapter.test.ts
@@ -1,5 +1,5 @@
-import type { EntityAdapter } from '../index'
-import { createEntityAdapter } from '../index'
+import type { EntityAdapter } from '../models'
+import { createEntityAdapter } from '../create_adapter'
 import type { PayloadAction } from '../../createAction'
 import { configureStore } from '../../configureStore'
 import { createSlice } from '../../createSlice'
diff --git a/packages/toolkit/src/entities/tests/state_selectors.test.ts b/packages/toolkit/src/entities/tests/state_selectors.test.ts
index 3afba41ac6..ef7a48e9eb 100644
--- a/packages/toolkit/src/entities/tests/state_selectors.test.ts
+++ b/packages/toolkit/src/entities/tests/state_selectors.test.ts
@@ -1,6 +1,6 @@
 import { createDraftSafeSelectorCreator } from '../../createDraftSafeSelector'
-import type { EntityAdapter, EntityState } from '../index'
-import { createEntityAdapter } from '../index'
+import type { EntityAdapter, EntityState } from '../models'
+import { createEntityAdapter } from '../create_adapter'
 import type { EntitySelectors } from '../models'
 import type { BookModel } from './fixtures/book'
 import { AClockworkOrange, AnimalFarm, TheGreatGatsby } from './fixtures/book'
@@ -147,6 +147,61 @@ describe('Entity State Selectors', () => {
       memoizeSpy.mockClear()
     })
   })
+  describe('named selectors', () => {
+    interface State {
+      books: EntityState<BookModel, string>
+    }
+
+    let adapter: EntityAdapter<BookModel, string>
+    let state: State
+
+    beforeEach(() => {
+      adapter = createEntityAdapter({
+        selectId: (book: BookModel) => book.id,
+      })
+
+      state = {
+        books: adapter.setAll(adapter.getInitialState(), [
+          AClockworkOrange,
+          AnimalFarm,
+          TheGreatGatsby,
+        ]),
+      }
+    })
+    it('should use the provided name and pluralName', () => {
+      const selectors = adapter.getSelectors(undefined, {
+        name: 'book',
+      })
+
+      expect(selectors.selectAllBooks).toBeTypeOf('function')
+      expect(selectors.selectTotalBooks).toBeTypeOf('function')
+      expect(selectors.selectBookById).toBeTypeOf('function')
+
+      expect(selectors.selectAllBooks(state.books)).toEqual([
+        AClockworkOrange,
+        AnimalFarm,
+        TheGreatGatsby,
+      ])
+      expect(selectors.selectTotalBooks(state.books)).toEqual(3)
+    })
+    it('should use the plural of the provided name', () => {
+      const selectors = adapter.getSelectors((state: State) => state.books, {
+        name: 'book',
+        pluralName: 'bookies',
+      })
+
+      expect(selectors.selectAllBookies).toBeTypeOf('function')
+      expect(selectors.selectTotalBookies).toBeTypeOf('function')
+      expect(selectors.selectBookById).toBeTypeOf('function')
+
+      expect(selectors.selectAllBookies(state)).toEqual([
+        AClockworkOrange,
+        AnimalFarm,
+        TheGreatGatsby,
+      ])
+      expect(selectors.selectTotalBookies(state)).toEqual(3)
+    })
+  })
 })
 
 function expectType<T>(t: T) {
diff --git a/packages/toolkit/src/entities/utils.ts b/packages/toolkit/src/entities/utils.ts
index 1d8c087235..5bc67bc646 100644
--- a/packages/toolkit/src/entities/utils.ts
+++ b/packages/toolkit/src/entities/utils.ts
@@ -66,3 +66,7 @@ export function splitAddedUpdatedEntities<T, Id extends EntityId>(
   }
   return [added, updated, existingIdsArray]
 }
+
+export function capitalize<S extends string>(str: S) {
+  return str && (str.replace(str[0], str[0].toUpperCase()) as Capitalize<S>)
+}
diff --git a/packages/toolkit/src/index.ts b/packages/toolkit/src/index.ts
index 0e06a93389..8cb44c3883 100644
--- a/packages/toolkit/src/index.ts
+++ b/packages/toolkit/src/index.ts
@@ -131,6 +131,10 @@ export type {
   IdSelector,
   Comparer,
 } from './entities/models'
+export {
+  createEntityMethods,
+  entityMethodsCreator,
+} from './entities/slice_creator'
 
 export {
   createAsyncThunk,