diff --git a/lib/config/types.ts b/lib/config/types.ts
index 7603028afe57188c664879f659e35423838a8af6..ee1824dd92968c2e4e4c2426a577f87f0f0b006d 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -181,7 +181,7 @@ export interface RegexManagerTemplates {
 export interface RegExManager extends RegexManagerTemplates {
   fileMatch: string[];
   matchStrings: string[];
-  matchStringsStrategy?: string;
+  matchStringsStrategy?: MatchStringsStrategy;
   autoReplaceStringTemplate?: string;
 }
 
@@ -231,6 +231,7 @@ export interface RenovateConfig
 
   defaultRegistryUrls?: string[];
   registryUrls?: string[] | null;
+  registryAliases?: Record<string, string>;
 
   repoIsOnboarded?: boolean;
   repoIsActivated?: boolean;
@@ -246,6 +247,7 @@ export interface RenovateConfig
   secrets?: Record<string, string>;
 
   constraints?: Record<string, string>;
+  skipInstalls?: boolean;
 }
 
 export interface AllConfig
diff --git a/lib/config/validation.spec.ts b/lib/config/validation.spec.ts
index 0191d6a42104fd1cdbe819327ff4d4854662e610..90794370797457aa64d0b632c920eea383a37eb9 100644
--- a/lib/config/validation.spec.ts
+++ b/lib/config/validation.spec.ts
@@ -550,7 +550,7 @@ describe('config/validation', () => {
         registryAliases: {
           sample: {
             example1: 'http://www.example.com',
-          },
+          } as unknown as string, // intentional incorrect config to check error message
         },
       };
       const { warnings, errors } = await configValidation.validateConfig(
diff --git a/lib/workers/repository/extract/extract-fingerprint-config.spec.ts b/lib/workers/repository/extract/extract-fingerprint-config.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e18da13569c136193067bac5b80aa39d264a6113
--- /dev/null
+++ b/lib/workers/repository/extract/extract-fingerprint-config.spec.ts
@@ -0,0 +1,115 @@
+import { mergeChildConfig } from '../../../config';
+import { getConfig } from '../../../config/defaults';
+import { getManagerList } from '../../../modules/manager';
+import { generateFingerprintConfig } from './extract-fingerprint-config';
+
+describe('workers/repository/extract/extract-fingerprint-config', () => {
+  it('filter with enabledManagers', () => {
+    const config = mergeChildConfig(getConfig(), {
+      registryAliases: {
+        stable: 'http://some.link', // intentionally placing the field incorrectly
+      },
+      ignorePaths: ['ignore-path-1'],
+      includePaths: ['include-path-1'],
+      npm: {
+        fileMatch: ['hero.json'],
+        ignorePaths: ['ignore-path-2'],
+        includePaths: ['include-path-2'],
+        registryAliases: {
+          notStable: 'http://some.link.2',
+        },
+      },
+      enabledManagers: ['npm', 'regex'],
+      regexManagers: [
+        {
+          fileMatch: ['js', '***$}{]]['],
+          matchStrings: ['^(?<depName>foo)(?<currentValue>bar)$'],
+          datasourceTemplate: 'maven',
+          versioningTemplate: 'gradle',
+        },
+      ],
+    });
+
+    const fingerprintConfig = generateFingerprintConfig(config);
+
+    expect(fingerprintConfig.managerList).toEqual(new Set(['npm', 'regex']));
+    expect(
+      fingerprintConfig.managers.find((manager) => manager.manager === 'npm')
+    ).toEqual({
+      enabled: true,
+      fileList: [],
+      fileMatch: ['(^|/)package\\.json$', 'hero.json'],
+      ignorePaths: ['ignore-path-2'],
+      includePaths: ['include-path-2'],
+      manager: 'npm',
+      npmrc: null,
+      npmrcMerge: false,
+      registryAliases: {
+        notStable: 'http://some.link.2',
+      },
+      skipInstalls: null,
+    });
+    expect(
+      fingerprintConfig.managers.find((manager) => manager.manager === 'regex')
+    ).toEqual({
+      fileMatch: ['js', '***$}{]]['],
+      ignorePaths: ['ignore-path-1'],
+      includePaths: ['include-path-1'],
+      fileList: [],
+      matchStrings: ['^(?<depName>foo)(?<currentValue>bar)$'],
+      datasourceTemplate: 'maven',
+      versioningTemplate: 'gradle',
+      enabled: true,
+      manager: 'regex',
+      npmrc: null,
+      npmrcMerge: false,
+      registryAliases: {
+        stable: 'http://some.link',
+      },
+      skipInstalls: null,
+    });
+  });
+
+  it('filter with all managers enabled', () => {
+    const config = mergeChildConfig(getConfig(), {
+      npmrc: 'some-string',
+      npmrcMerge: true,
+      npm: { fileMatch: ['hero.json'] },
+    });
+    const fingerprintConfig = generateFingerprintConfig(config);
+    expect(fingerprintConfig.managerList).toEqual(new Set(getManagerList()));
+    expect(
+      fingerprintConfig.managers.find((manager) => manager.manager === 'npm')
+    ).toEqual({
+      enabled: true,
+      fileList: [],
+      fileMatch: ['(^|/)package\\.json$', 'hero.json'],
+      ignorePaths: ['**/node_modules/**', '**/bower_components/**'],
+      includePaths: [],
+      manager: 'npm',
+      npmrc: 'some-string',
+      npmrcMerge: true,
+      registryAliases: {},
+      skipInstalls: null,
+    });
+    expect(
+      fingerprintConfig.managers.find(
+        (manager) => manager.manager === 'dockerfile'
+      )
+    ).toEqual({
+      enabled: true,
+      fileList: [],
+      fileMatch: ['(^|/|\\.)Dockerfile$', '(^|/)Dockerfile[^/]*$'],
+      ignorePaths: ['**/node_modules/**', '**/bower_components/**'],
+      includePaths: [],
+      manager: 'dockerfile',
+      npmrc: 'some-string',
+      npmrcMerge: true,
+      registryAliases: {},
+      skipInstalls: null,
+    });
+    expect(
+      fingerprintConfig.managers.find((manager) => manager.manager === 'regex')
+    ).toBeUndefined();
+  });
+});
diff --git a/lib/workers/repository/extract/extract-fingerprint-config.ts b/lib/workers/repository/extract/extract-fingerprint-config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f7089bc7d003f86bdd3e65ca4f459626c18c6b69
--- /dev/null
+++ b/lib/workers/repository/extract/extract-fingerprint-config.ts
@@ -0,0 +1,84 @@
+import { getManagerConfig, mergeChildConfig } from '../../../config';
+import type {
+  RegexManagerTemplates,
+  RenovateConfig,
+} from '../../../config/types';
+import { getManagerList } from '../../../modules/manager';
+import { validMatchFields } from '../../../modules/manager/regex/utils';
+import type { CustomExtractConfig } from '../../../modules/manager/types';
+import type { WorkerExtractConfig } from '../../types';
+
+export interface FingerprintExtractConfig {
+  managerList: Set<string>;
+  managers: WorkerExtractConfig[];
+}
+
+function getRegexManagerFields(
+  config: WorkerExtractConfig
+): CustomExtractConfig {
+  const regexFields = {} as CustomExtractConfig;
+  for (const field of validMatchFields.map(
+    (f) => `${f}Template` as keyof RegexManagerTemplates
+  )) {
+    if (config[field]) {
+      regexFields[field] = config[field];
+    }
+  }
+
+  return {
+    autoReplaceStringTemplate: config.autoReplaceStringTemplate,
+    matchStrings: config.matchStrings,
+    matchStringsStrategy: config.matchStringsStrategy,
+    ...regexFields,
+  };
+}
+
+function getFilteredManagerConfig(
+  config: WorkerExtractConfig
+): WorkerExtractConfig {
+  return {
+    ...(config.manager === 'regex' && getRegexManagerFields(config)),
+    manager: config.manager,
+    fileMatch: config.fileMatch,
+    npmrc: config.npmrc,
+    npmrcMerge: config.npmrcMerge,
+    enabled: config.enabled,
+    ignorePaths: config.ignorePaths ?? [],
+    includePaths: config.includePaths ?? [],
+    skipInstalls: config.skipInstalls,
+    registryAliases: config.registryAliases,
+    fileList: [],
+  };
+}
+
+export function generateFingerprintConfig(
+  config: RenovateConfig
+): FingerprintExtractConfig {
+  const managerExtractConfigs: WorkerExtractConfig[] = [];
+  let managerList: Set<string>;
+  const { enabledManagers } = config;
+  if (enabledManagers?.length) {
+    managerList = new Set(enabledManagers);
+  } else {
+    managerList = new Set(getManagerList());
+  }
+
+  for (const manager of managerList) {
+    const managerConfig = getManagerConfig(config, manager);
+    if (manager === 'regex') {
+      for (const regexManager of config.regexManagers ?? []) {
+        managerExtractConfigs.push({
+          ...mergeChildConfig(managerConfig, regexManager),
+          fileList: [],
+        });
+      }
+    } else {
+      managerExtractConfigs.push({ ...managerConfig, fileList: [] });
+    }
+  }
+
+  return {
+    managerList,
+    managers: managerExtractConfigs.map(getFilteredManagerConfig),
+  };
+}
diff --git a/lib/workers/repository/process/extract-update.spec.ts b/lib/workers/repository/process/extract-update.spec.ts
index de4eebf437da5f7d9161a6b39cc55e7f20d2e749..f67d0b65aac7bb3c15172feee9f4a55a048096de 100644
--- a/lib/workers/repository/process/extract-update.spec.ts
+++ b/lib/workers/repository/process/extract-update.spec.ts
@@ -1,9 +1,11 @@
-import { git, mocked } from '../../../../test/util';
+import { git, logger, mocked } from '../../../../test/util';
 import type { PackageFile } from '../../../modules/manager/types';
 import * as _repositoryCache from '../../../util/cache/repository';
+import type { BaseBranchCache } from '../../../util/cache/repository/types';
 import { fingerprint } from '../../../util/fingerprint';
+import { generateFingerprintConfig } from '../extract/extract-fingerprint-config';
 import * as _branchify from '../updates/branchify';
-import { extract, lookup, update } from './extract-update';
+import { extract, isCacheExtractValid, lookup, update } from './extract-update';
 
 jest.mock('./write');
 jest.mock('./sort');
@@ -59,6 +61,13 @@ describe('workers/repository/process/extract-update', () => {
         baseBranches: ['master', 'dev'],
         repoIsOnboarded: true,
         suppressNotifications: ['deprecationWarningIssues'],
+        enabledManagers: ['npm'],
+        javascript: {
+          labels: ['js'],
+        },
+        npm: {
+          addLabels: 'npm',
+        },
       };
       git.checkoutBranch.mockResolvedValueOnce('123test');
       repositoryCache.getCache.mockReturnValueOnce({ scan: {} });
@@ -77,7 +86,7 @@ describe('workers/repository/process/extract-update', () => {
         scan: {
           master: {
             sha: '123test',
-            configHash: fingerprint(config),
+            configHash: fingerprint(generateFingerprintConfig(config)),
             packageFiles,
           },
         },
@@ -88,4 +97,52 @@ describe('workers/repository/process/extract-update', () => {
       expect(res).toEqual(packageFiles);
     });
   });
+
+  describe('isCacheExtractValid()', () => {
+    let cachedExtract: BaseBranchCache = undefined as never;
+
+    it('undefined cache', () => {
+      expect(isCacheExtractValid('sha', 'hash', cachedExtract)).toBe(false);
+      expect(logger.logger.debug).toHaveBeenCalledTimes(0);
+    });
+
+    it('partial cache', () => {
+      cachedExtract = {
+        sha: 'sha',
+        configHash: undefined as never,
+        packageFiles: {},
+      };
+      expect(isCacheExtractValid('sha', 'hash', cachedExtract)).toBe(false);
+      expect(logger.logger.debug).toHaveBeenCalledTimes(0);
+    });
+
+    it('sha mismatch', () => {
+      cachedExtract.configHash = 'hash';
+      expect(isCacheExtractValid('new_sha', 'hash', cachedExtract)).toBe(false);
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        `Cached extract result cannot be used due to base branch SHA change (old=sha, new=new_sha)`
+      );
+      expect(logger.logger.debug).toHaveBeenCalledTimes(1);
+    });
+
+    it('config change', () => {
+      cachedExtract.sha = 'sha';
+      cachedExtract.configHash = 'hash';
+      expect(isCacheExtractValid('sha', 'new_hash', cachedExtract)).toBe(false);
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'Cached extract result cannot be used due to config change'
+      );
+      expect(logger.logger.debug).toHaveBeenCalledTimes(1);
+    });
+
+    it('valid cache and config', () => {
+      cachedExtract.sha = 'sha';
+      cachedExtract.configHash = 'hash';
+      expect(isCacheExtractValid('sha', 'hash', cachedExtract)).toBe(true);
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'Cached extract for sha=sha is valid and can be used'
+      );
+      expect(logger.logger.debug).toHaveBeenCalledTimes(1);
+    });
+  });
 });
diff --git a/lib/workers/repository/process/extract-update.ts b/lib/workers/repository/process/extract-update.ts
index 44894838d2a509bef33d6b33edcf579be55b3fe4..07550b2ffe3bfb879be98f5293c283d32a1db904 100644
--- a/lib/workers/repository/process/extract-update.ts
+++ b/lib/workers/repository/process/extract-update.ts
@@ -1,14 +1,15 @@
-// TODO #7154
 import is from '@sindresorhus/is';
 import type { RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
 import type { PackageFile } from '../../../modules/manager/types';
 import { getCache } from '../../../util/cache/repository';
+import type { BaseBranchCache } from '../../../util/cache/repository/types';
 import { checkGithubToken as ensureGithubToken } from '../../../util/check-token';
 import { fingerprint } from '../../../util/fingerprint';
 import { checkoutBranch, getBranchCommit } from '../../../util/git';
 import type { BranchConfig } from '../../types';
 import { extractAllDependencies } from '../extract';
+import { generateFingerprintConfig } from '../extract/extract-fingerprint-config';
 import { branchifyUpgrades } from '../updates/branchify';
 import { raiseDeprecationWarnings } from './deprecated';
 import { fetchUpdates } from './fetch';
@@ -61,6 +62,30 @@ function extractStats(
   return stats;
 }
 
+export function isCacheExtractValid(
+  baseBranchSha: string,
+  configHash: string,
+  cachedExtract?: BaseBranchCache
+): boolean {
+  if (!(cachedExtract?.sha && cachedExtract.configHash)) {
+    return false;
+  }
+  if (cachedExtract.sha !== baseBranchSha) {
+    logger.debug(
+      `Cached extract result cannot be used due to base branch SHA change (old=${cachedExtract.sha}, new=${baseBranchSha})`
+    );
+    return false;
+  }
+  if (cachedExtract.configHash !== configHash) {
+    logger.debug('Cached extract result cannot be used due to config change');
+    return false;
+  }
+  logger.debug(
+    `Cached extract for sha=${baseBranchSha} is valid and can be used`
+  );
+  return true;
+}
+
 export async function extract(
   config: RenovateConfig
 ): Promise<Record<string, PackageFile[]>> {
@@ -71,17 +96,9 @@ export async function extract(
   const cache = getCache();
   cache.scan ||= {};
   const cachedExtract = cache.scan[baseBranch!];
-  const { packageRules, ...remainingConfig } = config;
-  // Calculate hash excluding packageRules, because they're not applied during extract
-  const configHash = fingerprint(remainingConfig);
+  const configHash = fingerprint(generateFingerprintConfig(config));
   // istanbul ignore if
-  if (
-    cachedExtract?.sha === baseBranchSha &&
-    cachedExtract?.configHash === configHash
-  ) {
-    logger.debug(
-      `Found cached extract for ${baseBranch!} (sha=${baseBranchSha})`
-    );
+  if (isCacheExtractValid(baseBranchSha!, configHash, cachedExtract)) {
     packageFiles = cachedExtract.packageFiles;
     try {
       for (const files of Object.values(packageFiles)) {
@@ -98,6 +115,7 @@ export async function extract(
   } else {
     await checkoutBranch(baseBranch!);
     packageFiles = await extractAllDependencies(config);
+    // TODO: fix types (#7154)
     cache.scan[baseBranch!] = {
       sha: baseBranchSha!,
       configHash,
diff --git a/lib/workers/types.ts b/lib/workers/types.ts
index 692058889d6db2078f43627aae860d716bd0afb6..b1900a5977088a68d723e3bad60b3c987cfe46d0 100644
--- a/lib/workers/types.ts
+++ b/lib/workers/types.ts
@@ -2,7 +2,6 @@ import type { Merge } from 'type-fest';
 import type {
   GroupConfig,
   LegacyAdminConfig,
-  RegExManager,
   RenovateConfig,
   RenovateSharedConfig,
   ValidationMessage,
@@ -154,11 +153,8 @@ export interface WorkerExtractConfig extends ExtractConfig {
   manager: string;
   fileList: string[];
   fileMatch?: string[];
-  updateInternalDeps?: boolean;
   includePaths?: string[];
   ignorePaths?: string[];
-  regexManagers?: RegExManager[];
-  enabledManagers?: string[];
   enabled?: boolean;
 }