diff --git a/lib/workers/repository/init/merge.ts b/lib/workers/repository/init/merge.ts
index 111a98cd47cd38b7d0b7ca98cbaf753df5b18896..56bfca3cfe913be041926edbafba48b3609a55b9 100644
--- a/lib/workers/repository/init/merge.ts
+++ b/lib/workers/repository/init/merge.ts
@@ -170,9 +170,10 @@ export async function mergeRenovateConfig(
     throw error;
   }
   if (migratedConfig.warnings) {
-    returnConfig.warnings = returnConfig.warnings.concat(
-      migratedConfig.warnings
-    );
+    returnConfig.warnings = [
+      ...(returnConfig.warnings || []),
+      ...migratedConfig.warnings,
+    ];
   }
   delete migratedConfig.errors;
   delete migratedConfig.warnings;
diff --git a/lib/workers/repository/onboarding/branch/__snapshots__/index.spec.ts.snap b/lib/workers/repository/onboarding/branch/__snapshots__/index.spec.ts.snap
index c9031a0ff8a37ec81b01d8b96528364b49c3aadd..b94efadcf3a66c90cd448d86435cd8680c3a676c 100644
--- a/lib/workers/repository/onboarding/branch/__snapshots__/index.spec.ts.snap
+++ b/lib/workers/repository/onboarding/branch/__snapshots__/index.spec.ts.snap
@@ -6,3 +6,11 @@ exports[`workers/repository/onboarding/branch/index checkOnboardingBranch has de
 }
 "
 `;
+
+exports[`workers/repository/onboarding/branch/index checkOnboardingBranch uses discovered onboarding config 1`] = `
+"{
+  \\"$schema\\": \\"https://docs.renovatebot.com/renovate-schema.json\\",
+  \\"extends: [\\"some/renovate-config\\"]
+}
+"
+`;
diff --git a/lib/workers/repository/onboarding/branch/config.spec.ts b/lib/workers/repository/onboarding/branch/config.spec.ts
index 0ace4010ddfb54a4d8e3a597284406601be0d9ad..caa8982abc124ff1d0025ad395dd48d7fb57905c 100644
--- a/lib/workers/repository/onboarding/branch/config.spec.ts
+++ b/lib/workers/repository/onboarding/branch/config.spec.ts
@@ -1,7 +1,7 @@
 import { RenovateConfig, getConfig, getName } from '../../../../../test/util';
 import * as presets from '../../../../config/presets/local';
 import { PRESET_DEP_NOT_FOUND } from '../../../../config/presets/util';
-import { getOnboardingConfig } from './config';
+import { getOnboardingConfig, getOnboardingConfigContents } from './config';
 
 jest.mock('../../../../config/presets/local');
 
@@ -9,56 +9,72 @@ const mockedPresets = presets as jest.Mocked<typeof presets>;
 
 describe(getName(), () => {
   let config: RenovateConfig;
-  let onboardingConfig: string;
   beforeEach(() => {
     jest.clearAllMocks();
     config = getConfig();
     config.platform = 'github';
     config.repository = 'some/repo';
   });
+  describe('getOnboardingConfigContents', () => {
+    it('returns the JSON stringified onboarding config', async () => {
+      mockedPresets.getPreset.mockResolvedValueOnce({ enabled: true });
+      const contents = await getOnboardingConfigContents(config);
+      expect(mockedPresets.getPreset).toHaveBeenCalledTimes(1);
+      expect(contents).toEqual(
+        '{\n' +
+          '  "$schema": "https://docs.renovatebot.com/renovate-schema.json",\n' +
+          '  "extends": [\n' +
+          '    "local>some/renovate-config"\n' +
+          '  ]\n' +
+          '}\n'
+      );
+    });
+  });
   describe('getOnboardingConfig', () => {
     it('handles finding an organization preset', async () => {
       mockedPresets.getPreset.mockResolvedValueOnce({ enabled: true });
-      onboardingConfig = await getOnboardingConfig(config);
+      const onboardingConfig = await getOnboardingConfig(config);
       expect(mockedPresets.getPreset).toHaveBeenCalledTimes(1);
-      expect(JSON.parse(onboardingConfig).extends[0]).toEqual(
-        'local>some/renovate-config'
-      );
+      expect(onboardingConfig).toEqual({
+        $schema: 'https://docs.renovatebot.com/renovate-schema.json',
+        extends: ['local>some/renovate-config'],
+      });
     });
     it('handles finding an organization dot platform preset', async () => {
       mockedPresets.getPreset.mockRejectedValueOnce(
         new Error(PRESET_DEP_NOT_FOUND)
       );
       mockedPresets.getPreset.mockResolvedValueOnce({ enabled: true });
-      onboardingConfig = await getOnboardingConfig(config);
+      const onboardingConfig = await getOnboardingConfig(config);
       expect(mockedPresets.getPreset).toHaveBeenCalledTimes(2);
-      expect(JSON.parse(onboardingConfig).extends[0]).toEqual(
-        'local>some/.github:renovate-config'
-      );
+      expect(onboardingConfig).toEqual({
+        $schema: 'https://docs.renovatebot.com/renovate-schema.json',
+        extends: ['local>some/.github:renovate-config'],
+      });
     });
     it('handles not finding an organization preset', async () => {
       mockedPresets.getPreset.mockRejectedValue(
         new Error(PRESET_DEP_NOT_FOUND)
       );
-      onboardingConfig = await getOnboardingConfig(config);
+      const onboardingConfig = await getOnboardingConfig(config);
       expect(mockedPresets.getPreset).toHaveBeenCalledTimes(2);
-      expect(JSON.parse(onboardingConfig)).toEqual(config.onboardingConfig);
+      expect(onboardingConfig).toEqual(config.onboardingConfig);
     });
     it('ignores an unknown error', async () => {
       mockedPresets.getPreset.mockRejectedValue(
         new Error('unknown error for test')
       );
-      onboardingConfig = await getOnboardingConfig(config);
+      const onboardingConfig = await getOnboardingConfig(config);
       expect(mockedPresets.getPreset).toHaveBeenCalledTimes(2);
-      expect(JSON.parse(onboardingConfig)).toEqual(config.onboardingConfig);
+      expect(onboardingConfig).toEqual(config.onboardingConfig);
     });
     it('ignores unsupported platform', async () => {
       mockedPresets.getPreset.mockRejectedValue(
         new Error(`Unsupported platform 'dummy' for local preset.`)
       );
-      onboardingConfig = await getOnboardingConfig(config);
+      const onboardingConfig = await getOnboardingConfig(config);
       expect(mockedPresets.getPreset).toHaveBeenCalledTimes(2);
-      expect(JSON.parse(onboardingConfig)).toEqual(config.onboardingConfig);
+      expect(onboardingConfig).toEqual(config.onboardingConfig);
     });
   });
 });
diff --git a/lib/workers/repository/onboarding/branch/config.ts b/lib/workers/repository/onboarding/branch/config.ts
index 224f495b01d6696c9ced5eae8e4d8c0f738c0c2d..b96efdc78b735778e069f3f21b36773885fc0456 100644
--- a/lib/workers/repository/onboarding/branch/config.ts
+++ b/lib/workers/repository/onboarding/branch/config.ts
@@ -1,12 +1,15 @@
 import { getPreset } from '../../../../config/presets/local';
 import { PRESET_DEP_NOT_FOUND } from '../../../../config/presets/util';
-import type { RenovateConfig } from '../../../../config/types';
+import type {
+  RenovateConfig,
+  RenovateSharedConfig,
+} from '../../../../config/types';
 import { logger } from '../../../../logger';
 import { clone } from '../../../../util/clone';
 
-export async function getOnboardingConfig(
+async function getOnboardingConfig(
   config: RenovateConfig
-): Promise<string> {
+): Promise<RenovateSharedConfig> {
   let onboardingConfig = clone(config.onboardingConfig);
 
   let orgPreset: string;
@@ -65,5 +68,14 @@ export async function getOnboardingConfig(
   }
 
   logger.debug({ config: onboardingConfig }, 'onboarding config');
+  return onboardingConfig;
+}
+
+async function getOnboardingConfigContents(
+  config: RenovateConfig
+): Promise<string> {
+  const onboardingConfig = await getOnboardingConfig(config);
   return JSON.stringify(onboardingConfig, null, 2) + '\n';
 }
+
+export { getOnboardingConfig, getOnboardingConfigContents };
diff --git a/lib/workers/repository/onboarding/branch/create.spec.ts b/lib/workers/repository/onboarding/branch/create.spec.ts
index 6005cafb01dac023c59ed6b50ff6a3cc84b9d369..decbee29aec66891cfd9cd872fdf5a1d10c8781a 100644
--- a/lib/workers/repository/onboarding/branch/create.spec.ts
+++ b/lib/workers/repository/onboarding/branch/create.spec.ts
@@ -5,7 +5,7 @@ import { createOnboardingBranch } from './create';
 
 jest.mock('../../../../util/git');
 jest.mock('./config', () => ({
-  getOnboardingConfig: () =>
+  getOnboardingConfigContents: () =>
     JSON.stringify({
       foo: 'bar',
     }),
diff --git a/lib/workers/repository/onboarding/branch/create.ts b/lib/workers/repository/onboarding/branch/create.ts
index dc4c306fabd720d27947fe47e42e7d14fa06d785..e670134c6871484ae0a831cee38174c06bb9fa1a 100644
--- a/lib/workers/repository/onboarding/branch/create.ts
+++ b/lib/workers/repository/onboarding/branch/create.ts
@@ -4,7 +4,7 @@ import type { RenovateConfig } from '../../../../config/types';
 import { logger } from '../../../../logger';
 import { commitFiles } from '../../../../util/git';
 import { formatCommitMessagePrefix } from '../../util/commit-message';
-import { getOnboardingConfig } from './config';
+import { getOnboardingConfigContents } from './config';
 
 const defaultConfigFile = configFileNames[0];
 
@@ -12,7 +12,7 @@ export async function createOnboardingBranch(
   config: Partial<RenovateConfig>
 ): Promise<string | null> {
   logger.debug('createOnboardingBranch()');
-  const contents = await getOnboardingConfig(config);
+  const contents = await getOnboardingConfigContents(config);
   logger.debug('Creating onboarding branch');
 
   const configFile = configFileNames.includes(config.onboardingConfigFileName)
diff --git a/lib/workers/repository/onboarding/branch/index.spec.ts b/lib/workers/repository/onboarding/branch/index.spec.ts
index f2e56792bbcf11ab2a3e70248f9bd3eaf46b5108..10074a91a136f9f0887fc7f8da74e0a1e67bc723 100644
--- a/lib/workers/repository/onboarding/branch/index.spec.ts
+++ b/lib/workers/repository/onboarding/branch/index.spec.ts
@@ -7,16 +7,23 @@ import {
   git,
   platform,
 } from '../../../../../test/util';
+import {
+  REPOSITORY_FORKED,
+  REPOSITORY_NO_PACKAGE_FILES,
+} from '../../../../constants/error-messages';
 import { Pr } from '../../../../platform';
 import { PrState } from '../../../../types';
+import * as _config from './config';
 import * as _rebase from './rebase';
 import { checkOnboardingBranch } from '.';
 
 const rebase: any = _rebase;
+const configModule: any = _config;
 
 jest.mock('../../../../workers/repository/onboarding/branch/rebase');
 jest.mock('../../../../util/fs');
 jest.mock('../../../../util/git');
+jest.mock('./config');
 
 describe(getName(), () => {
   describe('checkOnboardingBranch', () => {
@@ -28,16 +35,51 @@ describe(getName(), () => {
       git.getFileList.mockResolvedValue([]);
     });
     it('throws if no package files', async () => {
-      await expect(checkOnboardingBranch(config)).rejects.toThrow();
+      await expect(checkOnboardingBranch(config)).rejects.toThrow(
+        REPOSITORY_NO_PACKAGE_FILES
+      );
     });
     it('throws if fork', async () => {
       config.isFork = true;
-      await expect(checkOnboardingBranch(config)).rejects.toThrow();
+      await expect(checkOnboardingBranch(config)).rejects.toThrow(
+        REPOSITORY_FORKED
+      );
     });
     it('has default onboarding config', async () => {
+      configModule.getOnboardingConfig.mockResolvedValue(
+        config.onboardingConfig
+      );
+      configModule.getOnboardingConfigContents.mockResolvedValue(
+        '{\n' +
+          '  "$schema": "https://docs.renovatebot.com/renovate-schema.json"\n' +
+          '}\n'
+      );
+      git.getFileList.mockResolvedValue(['package.json']);
+      fs.readLocalFile.mockResolvedValue('{}');
+      await checkOnboardingBranch(config);
+      expect(
+        git.commitFiles.mock.calls[0][0].files[0].contents
+      ).toMatchSnapshot();
+    });
+    it('uses discovered onboarding config', async () => {
+      configModule.getOnboardingConfig.mockResolvedValue({
+        onboardingBranch: 'test',
+      });
+      configModule.getOnboardingConfigContents.mockResolvedValue(
+        '{\n' +
+          '  "$schema": "https://docs.renovatebot.com/renovate-schema.json",\n' +
+          '  "extends: ["some/renovate-config"]\n' +
+          '}\n'
+      );
       git.getFileList.mockResolvedValue(['package.json']);
       fs.readLocalFile.mockResolvedValue('{}');
       await checkOnboardingBranch(config);
+      expect(configModule.getOnboardingConfigContents).toHaveBeenCalledWith({
+        ...config,
+        onboardingBranch: 'test',
+        renovateJsonPresent: true,
+        warnings: [],
+      });
       expect(
         git.commitFiles.mock.calls[0][0].files[0].contents
       ).toMatchSnapshot();
diff --git a/lib/workers/repository/onboarding/branch/index.ts b/lib/workers/repository/onboarding/branch/index.ts
index d9f63474bc54ac2d1a50626423832620a91af1b6..c38584c1f22e1066497e9dee7a6b5bff387aa626 100644
--- a/lib/workers/repository/onboarding/branch/index.ts
+++ b/lib/workers/repository/onboarding/branch/index.ts
@@ -1,3 +1,4 @@
+import { mergeChildConfig } from '../../../../config';
 import { getAdminConfig } from '../../../../config/admin';
 import type { RenovateConfig } from '../../../../config/types';
 import {
@@ -8,7 +9,9 @@ import { logger } from '../../../../logger';
 import { platform } from '../../../../platform';
 import { checkoutBranch } from '../../../../util/git';
 import { extractAllDependencies } from '../../extract';
+import { mergeRenovateConfig } from '../../init/merge';
 import { isOnboarded, onboardingPrExists } from './check';
+import { getOnboardingConfig } from './config';
 import { createOnboardingBranch } from './create';
 import { rebaseOnboardingBranch } from './rebase';
 
@@ -17,6 +20,7 @@ export async function checkOnboardingBranch(
 ): Promise<RenovateConfig> {
   logger.debug('checkOnboarding()');
   logger.trace({ config });
+  let onboardingBranch = config.onboardingBranch;
   const repoIsOnboarded = await isOnboarded(config);
   if (repoIsOnboarded) {
     logger.debug('Repo is onboarded');
@@ -42,22 +46,29 @@ export async function checkOnboardingBranch(
     }
   } else {
     logger.debug('Onboarding PR does not exist');
-    if (Object.entries(await extractAllDependencies(config)).length === 0) {
+    const onboardingConfig = await getOnboardingConfig(config);
+    let mergedConfig = mergeChildConfig(config, onboardingConfig);
+    mergedConfig = await mergeRenovateConfig(mergedConfig);
+    onboardingBranch = mergedConfig.onboardingBranch;
+
+    if (
+      Object.entries(await extractAllDependencies(mergedConfig)).length === 0
+    ) {
       throw new Error(REPOSITORY_NO_PACKAGE_FILES);
     }
     logger.debug('Need to create onboarding PR');
-    const commit = await createOnboardingBranch(config);
+    const commit = await createOnboardingBranch(mergedConfig);
     // istanbul ignore if
     if (commit) {
       logger.info(
-        { branch: config.onboardingBranch, commit, onboarding: true },
+        { branch: onboardingBranch, commit, onboarding: true },
         'Branch created'
       );
     }
   }
   if (!getAdminConfig().dryRun) {
-    await checkoutBranch(config.onboardingBranch);
+    await checkoutBranch(onboardingBranch);
   }
-  const branchList = [config.onboardingBranch];
-  return { ...config, repoIsOnboarded, branchList };
+  const branchList = [onboardingBranch];
+  return { ...config, repoIsOnboarded, onboardingBranch, branchList };
 }
diff --git a/lib/workers/repository/onboarding/branch/rebase.ts b/lib/workers/repository/onboarding/branch/rebase.ts
index 63354f51670ba6a1c4ed394ea215bd062da4782b..5080736251d3e8a4bce64b90fafdea811d76a066 100644
--- a/lib/workers/repository/onboarding/branch/rebase.ts
+++ b/lib/workers/repository/onboarding/branch/rebase.ts
@@ -8,7 +8,7 @@ import {
   isBranchModified,
   isBranchStale,
 } from '../../../../util/git';
-import { getOnboardingConfig } from './config';
+import { getOnboardingConfigContents } from './config';
 
 const defaultConfigFile = (config: RenovateConfig): string =>
   configFileNames.includes(config.onboardingConfigFileName)
@@ -42,7 +42,7 @@ export async function rebaseOnboardingBranch(
   }
   const configFile = defaultConfigFile(config);
   const existingContents = await getFile(configFile, config.onboardingBranch);
-  const contents = await getOnboardingConfig(config);
+  const contents = await getOnboardingConfigContents(config);
   if (
     contents === existingContents &&
     !(await isBranchStale(config.onboardingBranch))