diff --git a/packages/angular/cli/lib/config/workspace-schema.json b/packages/angular/cli/lib/config/workspace-schema.json
index 5fe427d4f415..d2427532c050 100644
--- a/packages/angular/cli/lib/config/workspace-schema.json
+++ b/packages/angular/cli/lib/config/workspace-schema.json
@@ -162,6 +162,9 @@
         "@schematics/angular:library": {
           "$ref": "../../../../schematics/angular/library/schema.json"
         },
+        "@schematics/angular:library-entrypoint": {
+          "$ref": "../../../../schematics/angular/library-entrypoint/schema.json"
+        },
         "@schematics/angular:pipe": {
           "$ref": "../../../../schematics/angular/pipe/schema.json"
         },
diff --git a/packages/schematics/angular/collection.json b/packages/schematics/angular/collection.json
index 5f691819544f..1eb4c9f1ae9b 100755
--- a/packages/schematics/angular/collection.json
+++ b/packages/schematics/angular/collection.json
@@ -117,6 +117,12 @@
       "schema": "./library/schema.json",
       "description": "Generate a library project for Angular."
     },
+    "library-entrypoint": {
+      "aliases": ["lib-entry"],
+      "factory": "./library-entrypoint",
+      "schema": "./library-entrypoint/schema.json",
+      "description": "Generate a library-entrypoint in an Angular library project."
+    },
     "web-worker": {
       "factory": "./web-worker",
       "schema": "./web-worker/schema.json",
diff --git a/packages/schematics/angular/library-entrypoint/files/README.md.template b/packages/schematics/angular/library-entrypoint/files/README.md.template
new file mode 100644
index 000000000000..1a1522b50d45
--- /dev/null
+++ b/packages/schematics/angular/library-entrypoint/files/README.md.template
@@ -0,0 +1,3 @@
+# <%= secondaryEntryPoint %>
+
+Secondary entry point of `<%= mainEntryPoint %>`. It can be used by importing from `<%= secondaryEntryPoint %>`
\ No newline at end of file
diff --git a/packages/schematics/angular/library-entrypoint/files/ng-package.json.template b/packages/schematics/angular/library-entrypoint/files/ng-package.json.template
new file mode 100644
index 000000000000..32bf2a8ebc81
--- /dev/null
+++ b/packages/schematics/angular/library-entrypoint/files/ng-package.json.template
@@ -0,0 +1,6 @@
+{
+  "$schema": "<%= relativePathToWorkspaceRoot %>/node_modules/ng-packagr/ng-package.schema.json",
+  "lib": {
+    "entryFile": "src/<%= entryFile %>.ts"
+  }
+}
\ No newline at end of file
diff --git a/packages/schematics/angular/library-entrypoint/index.ts b/packages/schematics/angular/library-entrypoint/index.ts
new file mode 100644
index 000000000000..6d73ed12dd8d
--- /dev/null
+++ b/packages/schematics/angular/library-entrypoint/index.ts
@@ -0,0 +1,95 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.dev/license
+ */
+
+import {
+  Rule,
+  SchematicsException,
+  Tree,
+  apply,
+  applyTemplates,
+  chain,
+  mergeWith,
+  move,
+  strings,
+  url,
+} from '@angular-devkit/schematics';
+import { JSONFile } from '../utility/json-file';
+import { relativePathToWorkspaceRoot } from '../utility/paths';
+import { buildDefaultPath, getWorkspace } from '../utility/workspace';
+import { ProjectType } from '../utility/workspace-models';
+import { Schema as LibraryOptions } from './schema';
+
+function updateTsConfig(packageName: string, ...paths: string[]) {
+  return (host: Tree) => {
+    if (!host.exists('tsconfig.json')) {
+      return host;
+    }
+
+    const file = new JSONFile(host, 'tsconfig.json');
+    const jsonPath = ['compilerOptions', 'paths', packageName];
+    const value = file.get(jsonPath);
+    file.modify(jsonPath, Array.isArray(value) ? [...paths, ...value] : paths);
+  };
+}
+
+export default function (options: LibraryOptions): Rule {
+  return async (host: Tree) => {
+    return async (host: Tree) => {
+      const workspace = await getWorkspace(host);
+      const project = workspace.projects.get(options.project);
+
+      if (!project) {
+        throw new SchematicsException(`Project "${options.project}" does not exist.`);
+      }
+
+      if (project?.extensions.projectType !== ProjectType.Library) {
+        throw new SchematicsException(
+          `Library entrypoint schematic requires a project type of "library".`,
+        );
+      }
+
+      const path = buildDefaultPath(project);
+      const libDir = `${path}/${options.name}`;
+      const pkgPath = `${project.root}/package.json`;
+
+      const pkg = host.readJson(pkgPath) as { name: string } | null;
+      if (pkg === null) {
+        throw new SchematicsException(`Could not find ${pkgPath}`);
+      }
+
+      const mainEntryPoint = pkg.name;
+      const secondaryEntryPoint = `${mainEntryPoint}/${options.name}`;
+
+      let folderName = mainEntryPoint.startsWith('@') ? mainEntryPoint.slice(1) : mainEntryPoint;
+      if (/[A-Z]/.test(folderName)) {
+        folderName = strings.dasherize(folderName);
+      }
+
+      const distRoot = `dist/${folderName}/${options.name}`;
+
+      const templateSource = apply(url('./files'), [
+        applyTemplates({
+          ...strings,
+          ...options,
+          mainEntryPoint,
+          secondaryEntryPoint,
+          relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(libDir),
+          packageName: options.name,
+          //TODO: fix this
+          entryFile: 'index.ts',
+        }),
+        move(libDir),
+      ]);
+
+      return chain([
+        mergeWith(templateSource),
+        updateTsConfig(secondaryEntryPoint, './' + distRoot),
+      ]);
+    };
+  };
+}
diff --git a/packages/schematics/angular/library-entrypoint/index_spec.ts b/packages/schematics/angular/library-entrypoint/index_spec.ts
new file mode 100644
index 000000000000..c06baff53a26
--- /dev/null
+++ b/packages/schematics/angular/library-entrypoint/index_spec.ts
@@ -0,0 +1,142 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.dev/license
+ */
+
+import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
+import { parse as parseJson } from 'jsonc-parser';
+import { Schema as LibraryOptions } from '../library/schema';
+import { Schema as WorkspaceOptions } from '../workspace/schema';
+import { Schema as GenerateLibrarySchema } from './schema';
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function getJsonFileContent(tree: UnitTestTree, path: string): any {
+  return parseJson(tree.readContent(path).toString());
+}
+
+describe('Secondary Entrypoint Schematic', () => {
+  const schematicRunner = new SchematicTestRunner(
+    '@schematics/ng_packagr',
+    require.resolve('../collection.json'),
+  );
+  const defaultOptions: GenerateLibrarySchema = {
+    name: 'foo-secondary',
+    project: 'foo',
+  };
+
+  const workspaceOptions: WorkspaceOptions = {
+    name: 'workspace',
+    newProjectRoot: 'projects',
+
+    version: '6.0.0',
+  };
+  const libaryOptions: LibraryOptions = {
+    name: 'foo',
+    standalone: true,
+    skipPackageJson: false,
+    skipTsConfig: false,
+    skipInstall: false,
+  };
+
+  let workspaceTree: UnitTestTree;
+  beforeEach(async () => {
+    workspaceTree = await schematicRunner.runSchematic('workspace', workspaceOptions);
+    workspaceTree = await schematicRunner.runSchematic('library', libaryOptions, workspaceTree);
+  });
+
+  it('should create correct files', async () => {
+    const tree = await schematicRunner.runSchematic(
+      'library-entrypoint',
+      { ...defaultOptions },
+      workspaceTree,
+    );
+    const files = tree.files;
+
+    expect(files).toEqual(
+      jasmine.arrayContaining([
+        '/projects/foo/src/lib/foo-secondary/README.md',
+        '/projects/foo/src/lib/foo-secondary/ng-package.json',
+      ]),
+    );
+  });
+
+  it('should set correct main and secondary entrypoints in the README', async () => {
+    const tree = await schematicRunner.runSchematic(
+      'library-entrypoint',
+      { ...defaultOptions },
+      workspaceTree,
+    );
+    const content = tree.readContent('/projects/foo/src/lib/foo-secondary/README.md');
+    expect(content).toMatch('# foo/foo-secondary');
+  });
+
+  it('should handle scope packages', async () => {
+    workspaceTree = await schematicRunner.runSchematic(
+      'library',
+      { ...libaryOptions, name: '@scope/package' },
+      workspaceTree,
+    );
+    const tree = await schematicRunner.runSchematic(
+      'library-entrypoint',
+      { ...defaultOptions, name: 'testing', project: '@scope/package' },
+      workspaceTree,
+    );
+    const files = tree.files;
+    expect(files).toEqual(
+      jasmine.arrayContaining([
+        '/projects/scope/package/src/lib/testing/README.md',
+        '/projects/scope/package/src/lib/testing/ng-package.json',
+      ]),
+    );
+  });
+
+  it(`should add paths mapping to the tsconfig`, async () => {
+    workspaceTree = await schematicRunner.runSchematic(
+      'library',
+      { ...libaryOptions, name: '@scope/package' },
+      workspaceTree,
+    );
+    const tree = await schematicRunner.runSchematic(
+      'library-entrypoint',
+      { ...defaultOptions, name: 'testing', project: '@scope/package' },
+      workspaceTree,
+    );
+
+    const tsConfigJson = getJsonFileContent(tree, 'tsconfig.json');
+    expect(tsConfigJson.compilerOptions.paths['@scope/package/testing']).toEqual([
+      './dist/scope/package/testing',
+    ]);
+  });
+
+  it(`should append to existing paths mappings`, async () => {
+    workspaceTree = await schematicRunner.runSchematic(
+      'library',
+      { ...libaryOptions, name: '@scope/package' },
+      workspaceTree,
+    );
+    workspaceTree.overwrite(
+      'tsconfig.json',
+      JSON.stringify({
+        compilerOptions: {
+          paths: {
+            'unrelated': ['./something/else.ts'],
+            '@scope/package/testing': ['libs/*'],
+          },
+        },
+      }),
+    );
+    const tree = await schematicRunner.runSchematic(
+      'library-entrypoint',
+      { ...defaultOptions, name: 'testing', project: '@scope/package' },
+      workspaceTree,
+    );
+    const tsConfigJson = getJsonFileContent(tree, 'tsconfig.json');
+    expect(tsConfigJson.compilerOptions.paths['@scope/package/testing']).toEqual([
+      './dist/scope/package/testing',
+      'libs/*',
+    ]);
+  });
+});
diff --git a/packages/schematics/angular/library-entrypoint/schema.json b/packages/schematics/angular/library-entrypoint/schema.json
new file mode 100644
index 000000000000..d7e98fa61e05
--- /dev/null
+++ b/packages/schematics/angular/library-entrypoint/schema.json
@@ -0,0 +1,28 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema",
+  "$id": "SchematicsLibrary",
+  "title": "Library Entrypoint Schema",
+  "type": "object",
+  "description": "Generate a library entrypoint in an Angular library project.",
+  "additionalProperties": false,
+  "properties": {
+    "name": {
+      "type": "string",
+      "description": "The name of the entrypoint to create.",
+      "pattern": "^[a-zA-Z0-9-._~]+/?[a-zA-Z0-9-._~]+$",
+      "$default": {
+        "$source": "argv",
+        "index": 0
+      },
+      "x-prompt": "What name would you like to use for the entrypoint?"
+    },
+    "project": {
+      "type": "string",
+      "description": "The name of the project.",
+      "$default": {
+        "$source": "projectName"
+      }
+    }
+  },
+  "required": ["name", "project"]
+}
diff --git a/tests/legacy-cli/e2e/tests/build/library-with-demo-app.ts b/tests/legacy-cli/e2e/tests/build/library-with-demo-app.ts
index 8e8d14ceb54f..45d8e3ea4966 100644
--- a/tests/legacy-cli/e2e/tests/build/library-with-demo-app.ts
+++ b/tests/legacy-cli/e2e/tests/build/library-with-demo-app.ts
@@ -12,8 +12,8 @@ import { updateJsonFile } from '../../utils/project';
 
 export default async function () {
   await ng('generate', 'library', 'mylib');
-  await createLibraryEntryPoint('secondary');
-  await createLibraryEntryPoint('another');
+  await ng('generate', 'lib-entry', 'secondary');
+  await ng('generate', 'lib-entry', 'another');
 
   // Scenario #1 where we use wildcard path mappings for secondary entry-points.
   await updateJsonFile('tsconfig.json', (json) => {
@@ -47,17 +47,3 @@ export default async function () {
 
   await ng('build');
 }
-
-async function createLibraryEntryPoint(name: string): Promise<void> {
-  await createDir(`projects/mylib/${name}`);
-  await writeFile(`projects/mylib/${name}/index.ts`, `export const foo = 'foo';`);
-
-  await writeFile(
-    `projects/mylib/${name}/ng-package.json`,
-    JSON.stringify({
-      lib: {
-        entryFile: 'index.ts',
-      },
-    }),
-  );
-}