diff --git a/lib/util/cache/repository/types.ts b/lib/util/cache/repository/types.ts
index 4a8c39478b1f12e51ad3de4eaf83579a31a3370b..de6af74256607b4ffe9c0249163b12847b899e23 100644
--- a/lib/util/cache/repository/types.ts
+++ b/lib/util/cache/repository/types.ts
@@ -8,6 +8,7 @@ import type { RepoInitConfig } from '../../../workers/repository/init/types';
 export interface BaseBranchCache {
   sha: string; // branch commit sha
   configHash: string; // object hash of config
+  extractionFingerprints: Record<string, string | undefined>; // matching manager fingerprints
   packageFiles: Record<string, PackageFile[]>; // extract result
 }
 
diff --git a/lib/workers/repository/extract/index.spec.ts b/lib/workers/repository/extract/index.spec.ts
index 9c2a6bcef18b2b2c00e5a0b9698d66dff630be71..4b39cf0be52636debc4fc9df048eda1f521d9bfc 100644
--- a/lib/workers/repository/extract/index.spec.ts
+++ b/lib/workers/repository/extract/index.spec.ts
@@ -30,7 +30,7 @@ describe('workers/repository/extract/index', () => {
       config.enabledManagers = ['npm'];
       managerFiles.getManagerPackageFiles.mockResolvedValue([{} as never]);
       const res = await extractAllDependencies(config);
-      expect(res).toEqual({ packageFiles: { npm: [{}] } });
+      expect(res).toMatchObject({ packageFiles: { npm: [{}] } });
     });
 
     it('warns if no packages found for a enabled manager', async () => {
diff --git a/lib/workers/repository/extract/index.ts b/lib/workers/repository/extract/index.ts
index e3e5e18ee7c731a5b28a8d9f9060eb5c656f0ce4..57395bf4075eb9ff91b927829d680314bdb0e2c1 100644
--- a/lib/workers/repository/extract/index.ts
+++ b/lib/workers/repository/extract/index.ts
@@ -2,7 +2,7 @@ import is from '@sindresorhus/is';
 import { getManagerConfig, mergeChildConfig } from '../../../config';
 import type { ManagerConfig, RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
-import { getManagerList } from '../../../modules/manager';
+import { getManagerList, hashMap } from '../../../modules/manager';
 import { getFileList } from '../../../util/git';
 import type { ExtractResult, WorkerExtractConfig } from '../../types';
 import { getMatchingFiles } from './file-match';
@@ -43,8 +43,15 @@ export async function extractAllDependencies(
 
   const extractResult: ExtractResult = {
     packageFiles: {},
+    extractionFingerprints: {},
   };
 
+  // Store the fingerprint of all managers which match any file (even if they do not find any dependencies)
+  // The cached result needs to be invalidated if the fingerprint of any matching manager changes
+  for (const { manager } of extractList) {
+    extractResult.extractionFingerprints[manager] = hashMap.get(manager);
+  }
+
   const extractResults = await Promise.all(
     extractList.map(async (managerConfig) => {
       const packageFiles = await getManagerPackageFiles(managerConfig);
diff --git a/lib/workers/repository/process/extract-update.spec.ts b/lib/workers/repository/process/extract-update.spec.ts
index f67d0b65aac7bb3c15172feee9f4a55a048096de..42380976007b7e4ba7cb69917bb47a5a536e87f5 100644
--- a/lib/workers/repository/process/extract-update.spec.ts
+++ b/lib/workers/repository/process/extract-update.spec.ts
@@ -87,6 +87,7 @@ describe('workers/repository/process/extract-update', () => {
           master: {
             sha: '123test',
             configHash: fingerprint(generateFingerprintConfig(config)),
+            extractionFingerprints: {},
             packageFiles,
           },
         },
@@ -99,19 +100,23 @@ describe('workers/repository/process/extract-update', () => {
   });
 
   describe('isCacheExtractValid()', () => {
-    let cachedExtract: BaseBranchCache = undefined as never;
+    let cachedExtract: BaseBranchCache;
 
-    it('undefined cache', () => {
-      expect(isCacheExtractValid('sha', 'hash', cachedExtract)).toBe(false);
-      expect(logger.logger.debug).toHaveBeenCalledTimes(0);
-    });
-
-    it('partial cache', () => {
+    beforeEach(() => {
       cachedExtract = {
         sha: 'sha',
         configHash: undefined as never,
+        extractionFingerprints: {},
         packageFiles: {},
       };
+    });
+
+    it('undefined cache', () => {
+      expect(isCacheExtractValid('sha', 'hash', undefined)).toBe(false);
+      expect(logger.logger.debug).toHaveBeenCalledTimes(0);
+    });
+
+    it('partial cache', () => {
       expect(isCacheExtractValid('sha', 'hash', cachedExtract)).toBe(false);
       expect(logger.logger.debug).toHaveBeenCalledTimes(0);
     });
@@ -126,7 +131,6 @@ describe('workers/repository/process/extract-update', () => {
     });
 
     it('config change', () => {
-      cachedExtract.sha = 'sha';
       cachedExtract.configHash = 'hash';
       expect(isCacheExtractValid('sha', 'new_hash', cachedExtract)).toBe(false);
       expect(logger.logger.debug).toHaveBeenCalledWith(
@@ -135,8 +139,30 @@ describe('workers/repository/process/extract-update', () => {
       expect(logger.logger.debug).toHaveBeenCalledTimes(1);
     });
 
+    it('invalid if no extractionFingerprints', () => {
+      cachedExtract.configHash = 'hash';
+      const { extractionFingerprints, ...restOfCache } = cachedExtract;
+      expect(
+        isCacheExtractValid(
+          'sha',
+          'hash',
+          restOfCache as never as BaseBranchCache
+        )
+      ).toBe(false);
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'Cached extract is missing extractionFingerprints, so cannot be used'
+      );
+      expect(logger.logger.debug).toHaveBeenCalledTimes(1);
+    });
+
+    it('invalid if changed fingerprints', () => {
+      cachedExtract.configHash = 'hash';
+      cachedExtract.extractionFingerprints = { npm: 'old-fingerprint' };
+      expect(isCacheExtractValid('sha', 'hash', cachedExtract)).toBe(false);
+      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(
diff --git a/lib/workers/repository/process/extract-update.ts b/lib/workers/repository/process/extract-update.ts
index 029636be8b333929f51584bf8345ffc494158647..763aadd539ff2484bb43a4497b9fd1c0fed884cd 100644
--- a/lib/workers/repository/process/extract-update.ts
+++ b/lib/workers/repository/process/extract-update.ts
@@ -1,6 +1,7 @@
 import is from '@sindresorhus/is';
 import type { RenovateConfig } from '../../../config/types';
 import { logger } from '../../../logger';
+import { hashMap } from '../../../modules/manager';
 import type { PackageFile } from '../../../modules/manager/types';
 import { getCache } from '../../../util/cache/repository';
 import type { BaseBranchCache } from '../../../util/cache/repository/types';
@@ -80,6 +81,27 @@ export function isCacheExtractValid(
     logger.debug('Cached extract result cannot be used due to config change');
     return false;
   }
+  if (!cachedExtract.extractionFingerprints) {
+    logger.debug(
+      'Cached extract is missing extractionFingerprints, so cannot be used'
+    );
+    return false;
+  }
+  const changedManagers = new Set();
+  for (const [manager, fingerprint] of Object.entries(
+    cachedExtract.extractionFingerprints
+  )) {
+    if (fingerprint !== hashMap.get(manager)) {
+      changedManagers.add(manager);
+    }
+  }
+  if (changedManagers.size > 0) {
+    logger.debug(
+      { changedManagers: [...changedManagers] },
+      'Manager fingerprint(s) have changed, extract cache cannot be reused'
+    );
+    return false;
+  }
   logger.debug(
     `Cached extract for sha=${baseBranchSha} is valid and can be used`
   );
@@ -114,12 +136,14 @@ export async function extract(
     }
   } else {
     await checkoutBranch(baseBranch!);
-    const extractResult = await extractAllDependencies(config);
-    packageFiles = extractResult?.packageFiles;
+    const extractResult = (await extractAllDependencies(config)) || {};
+    packageFiles = extractResult.packageFiles;
+    const { extractionFingerprints } = extractResult;
     // TODO: fix types (#7154)
     cache.scan[baseBranch!] = {
       sha: baseBranchSha!,
       configHash,
+      extractionFingerprints,
       packageFiles,
     };
     // Clean up cached branch extracts
diff --git a/lib/workers/types.ts b/lib/workers/types.ts
index fea5a440cd7f566a1cfc7bcb43aa930cb60a2f29..8236081cb5cd44cb3f7937b4df3daab277cdc11d 100644
--- a/lib/workers/types.ts
+++ b/lib/workers/types.ts
@@ -188,5 +188,6 @@ export interface UpgradeFingerprintConfig {
 }
 
 export interface ExtractResult {
+  extractionFingerprints: Record<string, string | undefined>;
   packageFiles: Record<string, PackageFile[]>;
 }