diff --git a/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap b/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap
index 7aa6e537ce89d78c90261ed7666ea2b447abf982..e913e5426085b9453f38865fc4cd7a4d2b3efc60 100644
--- a/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/process/lookup/__snapshots__/index.spec.ts.snap
@@ -8,7 +8,7 @@ exports[`workers/repository/process/lookup/index .lookupUpdates() handles digest
   "fixedVersion": "8.0.0",
   "homepage": undefined,
   "isSingleVersion": true,
-  "registryUrl": undefined,
+  "registryUrl": "https://index.docker.io",
   "sourceUrl": "https://github.com/nodejs/node",
   "updates": [
     {
@@ -54,7 +54,7 @@ exports[`workers/repository/process/lookup/index .lookupUpdates() handles digest
   "dependencyUrl": undefined,
   "fixedVersion": "8.1.0",
   "homepage": undefined,
-  "registryUrl": undefined,
+  "registryUrl": "https://index.docker.io",
   "sourceUrl": "https://github.com/nodejs/node",
   "updates": [
     {
@@ -77,7 +77,7 @@ exports[`workers/repository/process/lookup/index .lookupUpdates() handles digest
   "fixedVersion": "8.0.0",
   "homepage": undefined,
   "isSingleVersion": true,
-  "registryUrl": undefined,
+  "registryUrl": "https://index.docker.io",
   "sourceUrl": "https://github.com/nodejs/node",
   "updates": [
     {
@@ -128,26 +128,6 @@ exports[`workers/repository/process/lookup/index .lookupUpdates() handles git su
 }
 `;
 
-exports[`workers/repository/process/lookup/index .lookupUpdates() handles replacements 1`] = `
-{
-  "changelogUrl": undefined,
-  "currentVersion": "1.4.1",
-  "dependencyUrl": undefined,
-  "fixedVersion": "1.4.1",
-  "homepage": undefined,
-  "registryUrl": "https://registry.npmjs.org",
-  "sourceUrl": "https://github.com/kriskowal/q",
-  "updates": [
-    {
-      "newName": "r",
-      "newValue": "2.0.0",
-      "updateType": "replacement",
-    },
-  ],
-  "versioning": "npm",
-  "warnings": [],
-}
-`;
 
 exports[`workers/repository/process/lookup/index .lookupUpdates() handles sourceUrl packageRules with version restrictions 1`] = `
 {
@@ -556,7 +536,7 @@ exports[`workers/repository/process/lookup/index .lookupUpdates() skips uncompat
   "fixedVersion": "8",
   "homepage": undefined,
   "isSingleVersion": true,
-  "registryUrl": undefined,
+  "registryUrl": "https://index.docker.io",
   "sourceUrl": "https://github.com/nodejs/node",
   "updates": [
     {
@@ -615,7 +595,7 @@ exports[`workers/repository/process/lookup/index .lookupUpdates() skips uncompat
   "fixedVersion": "8.1.0",
   "homepage": undefined,
   "isSingleVersion": true,
-  "registryUrl": undefined,
+  "registryUrl": "https://index.docker.io",
   "sourceUrl": "https://github.com/nodejs/node",
   "updates": [
     {
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index 1efd5c8ae30f85bafdad22877e3565c7b37c7586..40f8e62f9970f1d3192d40e5ad3bb9ca9e56768c 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -1,6 +1,6 @@
 import { Fixtures } from '../../../../../test/fixtures';
 import * as httpMock from '../../../../../test/http-mock';
-import { getConfig, mocked, partial } from '../../../../../test/util';
+import { getConfig, partial } from '../../../../../test/util';
 import { CONFIG_VALIDATION } from '../../../../constants/error-messages';
 import { DockerDatasource } from '../../../../modules/datasource/docker';
 import { GitRefsDatasource } from '../../../../modules/datasource/git-refs';
@@ -18,8 +18,6 @@ import * as githubGraphql from '../../../../util/github/graphql';
 import type { LookupUpdateConfig } from './types';
 import * as lookup from '.';
 
-jest.mock('../../../../modules/datasource/docker');
-
 const fixtureRoot = '../../../../config/npm';
 const qJson = {
   ...Fixtures.getJson('01.json', fixtureRoot),
@@ -33,8 +31,6 @@ const typescriptJson = Fixtures.get('typescript.json', fixtureRoot);
 const vueJson = Fixtures.get('vue.json', fixtureRoot);
 const webpackJson = Fixtures.get('webpack.json', fixtureRoot);
 
-const docker = mocked(DockerDatasource.prototype);
-
 let config: LookupUpdateConfig;
 
 describe('workers/repository/process/lookup/index', () => {
@@ -43,7 +39,16 @@ describe('workers/repository/process/lookup/index', () => {
     'getReleases'
   );
 
+  const getDockerReleases = jest.spyOn(
+    DockerDatasource.prototype,
+    'getReleases'
+  );
+
+  const getDockerDigest = jest.spyOn(DockerDatasource.prototype, 'getDigest');
+
   beforeEach(() => {
+    // TODO: fix wrong tests
+    jest.resetAllMocks();
     // TODO: fix types #7154
     config = partial<LookupUpdateConfig>(getConfig() as never);
     config.manager = 'npm';
@@ -1541,7 +1546,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.datasource = DockerDatasource.id;
       config.pinDigests = true;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           {
             version: '8.0.0',
@@ -1551,8 +1556,8 @@ describe('workers/repository/process/lookup/index', () => {
           },
         ],
       });
-      docker.getDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
-      docker.getDigest.mockResolvedValueOnce('sha256:0123456789abcdef');
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      getDockerDigest.mockResolvedValueOnce('sha256:0123456789abcdef');
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot({
         currentVersion: '8.0.0',
@@ -1578,7 +1583,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.versioning = dockerVersioningId;
       config.datasource = DockerDatasource.id;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           { version: '8.1.0' },
           { version: '8.1.5' },
@@ -1602,7 +1607,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.versioning = dockerVersioningId;
       config.datasource = DockerDatasource.id;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         registryUrl: 'https://index.docker.io',
         releases: [
           { version: '8.1.0' },
@@ -1635,7 +1640,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.versioning = dockerVersioningId;
       config.datasource = DockerDatasource.id;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           { version: '8.1.0' },
           { version: '8.1.5' },
@@ -1659,7 +1664,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.datasource = DockerDatasource.id;
       config.pinDigests = true;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           {
             version: '8.0.0',
@@ -1669,7 +1674,7 @@ describe('workers/repository/process/lookup/index', () => {
           },
         ],
       });
-      docker.getDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot({
         updates: [
@@ -1688,7 +1693,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.datasource = DockerDatasource.id;
       config.pinDigests = true;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           {
             version: '8.0.0',
@@ -1701,7 +1706,7 @@ describe('workers/repository/process/lookup/index', () => {
           },
         ],
       });
-      docker.getDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot({
         updates: [
@@ -1720,7 +1725,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.packageName = 'node';
       config.datasource = DockerDatasource.id;
       config.pinDigests = true;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           {
             version: '8.0.0',
@@ -1733,7 +1738,7 @@ describe('workers/repository/process/lookup/index', () => {
           },
         ],
       });
-      docker.getDigest.mockResolvedValueOnce(null);
+      getDockerDigest.mockResolvedValueOnce(null);
       const res = await lookup.lookupUpdates(config);
       expect(res.updates).toHaveLength(0);
     });
@@ -1744,7 +1749,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.datasource = DockerDatasource.id;
       config.currentDigest = 'sha256:zzzzzzzzzzzzzzz';
       config.pinDigests = true;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           {
             version: '8.0.0',
@@ -1754,8 +1759,8 @@ describe('workers/repository/process/lookup/index', () => {
           },
         ],
       });
-      docker.getDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
-      docker.getDigest.mockResolvedValueOnce('sha256:0123456789abcdef');
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      getDockerDigest.mockResolvedValueOnce('sha256:0123456789abcdef');
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot({
         updates: [
@@ -1779,7 +1784,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.datasource = DockerDatasource.id;
       config.currentDigest = 'sha256:zzzzzzzzzzzzzzz';
       config.pinDigests = true;
-      docker.getReleases.mockResolvedValueOnce({
+      getDockerReleases.mockResolvedValueOnce({
         releases: [
           {
             version: 'alpine',
@@ -1792,7 +1797,7 @@ describe('workers/repository/process/lookup/index', () => {
           },
         ],
       });
-      docker.getDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
       const res = await lookup.lookupUpdates(config);
       expect(res).toMatchSnapshot({
         updates: [
@@ -1841,7 +1846,102 @@ describe('workers/repository/process/lookup/index', () => {
       });
     });
 
-    it('handles replacements', async () => {
+    it('handles replacements - name only without pinDigests enabled', async () => {
+      config.packageName = 'openjdk';
+      config.currentValue = '17.0.0';
+      config.datasource = DockerDatasource.id;
+      config.versioning = dockerVersioningId;
+      // This config is normally set when packageRules are applied
+      config.replacementName = 'eclipse-temurin';
+      getDockerReleases.mockResolvedValueOnce({
+        releases: [
+          {
+            version: '17.0.0',
+          },
+          {
+            version: '18.0.0',
+          },
+        ],
+      });
+
+      expect((await lookup.lookupUpdates(config)).updates).toMatchObject([
+        {
+          updateType: 'replacement',
+          newName: 'eclipse-temurin',
+          newValue: '17.0.0',
+        },
+        {
+          updateType: 'major',
+          newMajor: 18,
+          newValue: '18.0.0',
+          newVersion: '18.0.0',
+        },
+      ]);
+    });
+
+    it('handles replacements - name only with pinDigests enabled', async () => {
+      config.packageName = 'openjdk';
+      config.currentValue = '17.0.0';
+      config.pinDigests = true;
+      config.datasource = DockerDatasource.id;
+      config.versioning = dockerVersioningId;
+      // This config is normally set when packageRules are applied
+      config.replacementName = 'eclipse-temurin';
+      getDockerReleases.mockResolvedValueOnce({
+        releases: [
+          {
+            version: '17.0.0',
+          },
+          {
+            version: '18.0.0',
+          },
+        ],
+      });
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      getDockerDigest.mockResolvedValueOnce('sha256:0123456789abcdef');
+      getDockerDigest.mockResolvedValueOnce('sha256:pin0987654321');
+
+      expect((await lookup.lookupUpdates(config)).updates).toMatchObject([
+        {
+          updateType: 'replacement',
+          newName: 'eclipse-temurin',
+          newValue: '17.0.0',
+          newDigest: 'sha256:abcdef1234567890',
+        },
+        {
+          updateType: 'major',
+          newMajor: 18,
+          newValue: '18.0.0',
+          newVersion: '18.0.0',
+          newDigest: 'sha256:0123456789abcdef',
+        },
+        {
+          isPinDigest: true,
+          newDigest: 'sha256:pin0987654321',
+          newValue: '17.0.0',
+          updateType: 'pinDigest',
+        },
+      ]);
+    });
+
+    it('handles replacements - name only no version/tag', async () => {
+      config.packageName = 'openjdk';
+      config.currentValue = undefined;
+      config.datasource = DockerDatasource.id;
+      config.versioning = dockerVersioningId;
+      // This config is normally set when packageRules are applied
+      config.replacementName = 'eclipse-temurin';
+      getDockerDigest.mockResolvedValueOnce('sha256:abcdef1234567890');
+      expect((await lookup.lookupUpdates(config)).updates).toMatchObject([
+        {
+          updateType: 'replacement',
+          newName: 'eclipse-temurin',
+          newValue: undefined,
+        },
+      ]);
+    });
+
+    it('handles replacements - name and version', async () => {
       config.currentValue = '1.4.1';
       config.packageName = 'q';
       // This config is normally set when packageRules are applied
@@ -1849,8 +1949,13 @@ describe('workers/repository/process/lookup/index', () => {
       config.replacementVersion = '2.0.0';
       config.datasource = NpmDatasource.id;
       httpMock.scope('https://registry.npmjs.org').get('/q').reply(200, qJson);
-      const res = await lookup.lookupUpdates(config);
-      expect(res).toMatchSnapshot();
+      expect((await lookup.lookupUpdates(config)).updates).toMatchObject([
+        {
+          updateType: 'replacement',
+          newName: 'r',
+          newValue: '2.0.0',
+        },
+      ]);
     });
 
     it('rollback for invalid version to last stable version', async () => {
diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts
index 522745e27a0a5a1c9b1382c7b7037e5156c7a01a..a262baf9922a7fa12d70483edf5e3f3fdc823a4d 100644
--- a/lib/workers/repository/process/lookup/index.ts
+++ b/lib/workers/repository/process/lookup/index.ts
@@ -156,6 +156,15 @@ export async function lookupUpdates(
         res.updates.push(rollback);
       }
       let rangeStrategy = getRangeStrategy(config);
+
+      if (config.replacementName && !config.replacementVersion) {
+        res.updates.push({
+          updateType: 'replacement',
+          newName: config.replacementName,
+          newValue: currentValue!,
+        });
+      }
+
       if (config.replacementName && config.replacementVersion) {
         res.updates.push({
           updateType: 'replacement',
@@ -335,6 +344,19 @@ export async function lookupUpdates(
       } else {
         delete res.skipReason;
       }
+    } else if (
+      !currentValue &&
+      config.replacementName &&
+      !config.replacementVersion
+    ) {
+      logger.debug(
+        `Handle name-only replacement for ${packageName} without current version`
+      );
+      res.updates.push({
+        updateType: 'replacement',
+        newName: config.replacementName,
+        newValue: currentValue!,
+      });
     } else {
       res.skipReason = 'invalid-value';
     }
@@ -427,6 +449,8 @@ export async function lookupUpdates(
       .filter((update) => update.newDigest !== null)
       .filter(
         (update) =>
+          (update.newName && update.newName !== packageName) ||
+          update.isReplacement ||
           update.newValue !== currentValue ||
           update.isLockfileUpdate ||
           // TODO #7154