diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
index 57abae96f853c..fb0e50785eca2 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java
@@ -6,6 +6,7 @@
 import static io.quarkus.deployment.util.ReflectUtil.toError;
 import static io.quarkus.deployment.util.ReflectUtil.typeOfParameter;
 import static io.quarkus.deployment.util.ReflectUtil.unwrapInvocationTargetException;
+import static java.util.stream.Collectors.toSet;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -55,11 +56,13 @@
 import io.quarkus.runtime.configuration.ConfigurationException;
 import io.quarkus.runtime.configuration.HyphenateEnumConverter;
 import io.quarkus.runtime.configuration.NameIterator;
+import io.quarkus.runtime.configuration.PropertiesUtil;
 import io.smallrye.config.Converters;
 import io.smallrye.config.EnvConfigSource;
 import io.smallrye.config.Expressions;
 import io.smallrye.config.SmallRyeConfig;
 import io.smallrye.config.SmallRyeConfigBuilder;
+import io.smallrye.config.SysPropConfigSource;
 
 /**
  * A configuration reader.
@@ -91,14 +94,17 @@ public BuildTimeConfigurationReader(final List<Class<?>> configRoots) {
         List<RootDefinition> buildTimeRoots = new ArrayList<>();
         Map<Class<?>, GroupDefinition> groups = new HashMap<>();
         for (Class<?> configRoot : configRoots) {
+            String prefix = "quarkus";
             String name = ConfigItem.HYPHENATED_ELEMENT_NAME;
             ConfigPhase phase = ConfigPhase.BUILD_TIME;
             ConfigRoot annotation = configRoot.getAnnotation(ConfigRoot.class);
             if (annotation != null) {
+                prefix = annotation.prefix();
                 name = annotation.name();
                 phase = annotation.phase();
             }
             RootDefinition.Builder defBuilder = new RootDefinition.Builder();
+            defBuilder.setPrefix(prefix);
             defBuilder.setConfigPhase(phase);
             defBuilder.setRootName(name);
             processClass(defBuilder, configRoot, groups);
@@ -272,9 +278,7 @@ final class ReadOperation {
 
         ReadResult run() {
             final StringBuilder nameBuilder;
-            nameBuilder = new StringBuilder().append("quarkus");
-            // eager init first
-            int len = nameBuilder.length();
+            nameBuilder = new StringBuilder();
             for (RootDefinition root : buildTimeVisibleRoots) {
                 Class<?> clazz = root.getConfigurationClass();
                 Object instance;
@@ -292,23 +296,21 @@ ReadResult run() {
                     throw toError(e);
                 }
                 objectsByRootClass.put(clazz, instance);
-                String rootName = root.getRootName();
-                if (!rootName.isEmpty()) {
-                    nameBuilder.append('.').append(rootName);
-                }
+                nameBuilder.append(root.getName());
                 readConfigGroup(root, instance, nameBuilder);
-                nameBuilder.setLength(len);
+                nameBuilder.setLength(0);
             }
+
+            Set<String> registeredRoots = allRoots.stream().map(RootDefinition::getPrefix).collect(toSet());
             // sweep-up
             SmallRyeConfig runtimeDefaultsConfig = getConfigForRuntimeDefaults();
-            for (String propertyName : getAllProperties()) {
+            for (String propertyName : getAllProperties(registeredRoots)) {
                 if (propertyName.equals(ConfigSource.CONFIG_ORDINAL)) {
                     continue;
                 }
 
                 NameIterator ni = new NameIterator(propertyName);
-                if (ni.hasNext() && ni.nextSegmentEquals("quarkus")) {
-                    ni.next();
+                if (ni.hasNext() && PropertiesUtil.isPropertyInRoot(registeredRoots, ni)) {
                     // build time patterns
                     Container matched = buildTimePatternMap.match(ni);
                     if (matched instanceof FieldContainer) {
@@ -337,7 +339,6 @@ ReadResult run() {
                     }
                     // build time (run time visible) patterns
                     ni.goToStart();
-                    ni.next();
                     matched = buildTimeRunTimePatternMap.match(ni);
                     if (matched instanceof FieldContainer) {
                         ni.goToEnd();
@@ -369,7 +370,6 @@ ReadResult run() {
                     }
                     // run time patterns
                     ni.goToStart();
-                    ni.next();
                     matched = runTimePatternMap.match(ni);
                     if (matched != null) {
                         // it's a specified run-time default (record for later)
@@ -380,7 +380,6 @@ ReadResult run() {
                     }
                     // also check for the bootstrap properties since those need to be added to specifiedRunTimeDefaultValues as well
                     ni.goToStart();
-                    ni.next();
                     matched = bootstrapPatternMap.match(ni);
                     if (matched != null) {
                         // it's a specified run-time default (record for later)
@@ -732,11 +731,23 @@ private Converter<?> getConverter(SmallRyeConfig config, Field field, ConverterT
          * We collect all properties from ConfigSources, because Config#getPropertyNames exclude the active profiled
          * properties, meaning that the property is written in the default config source unprofiled. This may cause
          * issues if we run with a different profile and fallback to defaults.
+         *
+         * We also filter the properties coming from the System with the registered roots, because we don't want to
+         * record properties set by the compiling JVM (or other properties set that are only related to the build).
          */
-        private Set<String> getAllProperties() {
+        private Set<String> getAllProperties(final Set<String> registeredRoots) {
             Set<String> properties = new HashSet<>();
             for (ConfigSource configSource : config.getConfigSources()) {
-                properties.addAll(configSource.getPropertyNames());
+                if (configSource instanceof SysPropConfigSource) {
+                    for (String propertyName : configSource.getProperties().keySet()) {
+                        NameIterator ni = new NameIterator(propertyName);
+                        if (ni.hasNext() && PropertiesUtil.isPropertyInRoot(registeredRoots, ni)) {
+                            properties.add(propertyName);
+                        }
+                    }
+                } else {
+                    properties.addAll(configSource.getPropertyNames());
+                }
             }
             for (String propertyName : config.getPropertyNames()) {
                 properties.add(propertyName);
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java
index 59df69b94ed5e..268b44949c0c7 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/DefaultValuesConfigurationSource.java
@@ -29,10 +29,7 @@ public Set<String> getPropertyNames() {
     }
 
     public String getValue(final String propertyName) {
-        if (!propertyName.startsWith("quarkus.")) {
-            return null;
-        }
-        final Container match = leafs.match(propertyName.substring(8));
+        final Container match = leafs.match(propertyName);
         if (match == null) {
             return null;
         }
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/PropertiesUtil.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/PropertiesUtil.java
deleted file mode 100644
index c8eb215cdb1f6..0000000000000
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/PropertiesUtil.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package io.quarkus.deployment.configuration;
-
-public class PropertiesUtil {
-    private PropertiesUtil() {
-    }
-
-    public static boolean needsEscape(int codePoint) {
-        return codePoint == '#' || codePoint == '!' || codePoint == '=' || codePoint == ':';
-    }
-
-    public static boolean needsEscapeForKey(int codePoint) {
-        return Character.isSpaceChar(codePoint) || needsEscape(codePoint);
-    }
-
-    public static boolean needsEscapeForValueFirst(int codePoint) {
-        return needsEscapeForKey(codePoint);
-    }
-
-    public static boolean needsEscapeForValueSubsequent(int codePoint) {
-        return needsEscape(codePoint);
-    }
-
-    public static String quotePropertyName(String name) {
-        final int length = name.length();
-        int cp;
-        for (int i = 0; i < length; i = name.offsetByCodePoints(i, 1)) {
-            cp = name.codePointAt(i);
-            if (needsEscapeForKey(cp)) {
-                final StringBuilder b = new StringBuilder(length + (length >> 2));
-                // get leading section
-                b.append(name, 0, i);
-                // and continue with escaping as needed
-                b.append('\\').appendCodePoint(cp);
-                for (i = name.offsetByCodePoints(i, 1); i < length; i = name.offsetByCodePoints(i, 1)) {
-                    cp = name.codePointAt(i);
-                    if (needsEscapeForKey(cp)) {
-                        b.append('\\');
-                    }
-                    b.appendCodePoint(cp);
-                }
-                return b.toString();
-            }
-        }
-        // no escaping needed - majority case
-        return name;
-    }
-
-    public static String quotePropertyValue(String value) {
-        final int length = value.length();
-        int cp;
-        for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
-            cp = value.codePointAt(i);
-            if (i == 0 ? needsEscapeForValueFirst(cp) : needsEscapeForValueSubsequent(cp)) {
-                final StringBuilder b = new StringBuilder(length + (length >> 2));
-                // get leading section
-                b.append(value, 0, i);
-                // and continue with escaping as needed
-                b.append('\\').appendCodePoint(cp);
-                for (i = value.offsetByCodePoints(i, 1); i < length; i = value.offsetByCodePoints(i, 1)) {
-                    cp = value.codePointAt(i);
-                    if (needsEscapeForValueSubsequent(cp)) {
-                        b.append('\\');
-                    }
-                    b.appendCodePoint(cp);
-                }
-                return b.toString();
-            }
-        }
-        // no escaping needed - majority case
-        return value;
-    }
-}
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java
index ee5ebd04d064d..1594f0ab9fc05 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/RunTimeConfigurationGenerator.java
@@ -1,12 +1,16 @@
 package io.quarkus.deployment.configuration;
 
 import static io.quarkus.deployment.util.ReflectUtil.reportError;
+import static io.quarkus.runtime.annotations.ConfigPhase.BOOTSTRAP;
+import static io.quarkus.runtime.annotations.ConfigPhase.BUILD_AND_RUN_TIME_FIXED;
+import static io.quarkus.runtime.annotations.ConfigPhase.RUN_TIME;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -66,6 +70,7 @@
 import io.quarkus.runtime.configuration.HyphenateEnumConverter;
 import io.quarkus.runtime.configuration.NameIterator;
 import io.quarkus.runtime.configuration.ProfileManager;
+import io.quarkus.runtime.configuration.PropertiesUtil;
 import io.quarkus.runtime.configuration.QuarkusConfigFactory;
 import io.quarkus.runtime.configuration.RuntimeConfigSource;
 import io.quarkus.runtime.configuration.RuntimeConfigSourceFactory;
@@ -206,8 +211,6 @@ public final class RunTimeConfigurationGenerator {
             boolean.class, String.class);
     static final MethodDescriptor NI_NEXT = MethodDescriptor.ofMethod(NameIterator.class, "next", void.class);
     static final MethodDescriptor NI_PREVIOUS = MethodDescriptor.ofMethod(NameIterator.class, "previous", void.class);
-    static final MethodDescriptor NI_PREVIOUS_EQUALS = MethodDescriptor.ofMethod(NameIterator.class, "previousSegmentEquals",
-            boolean.class, String.class);
 
     static final MethodDescriptor OBJ_TO_STRING = MethodDescriptor.ofMethod(Object.class, "toString", String.class);
 
@@ -253,6 +256,11 @@ public final class RunTimeConfigurationGenerator {
     static final MethodDescriptor SRCB_BUILD = MethodDescriptor.ofMethod(SmallRyeConfigBuilder.class, "build",
             SmallRyeConfig.class);
 
+    static final MethodDescriptor PU_IS_PROPERTY_IN_ROOT = MethodDescriptor.ofMethod(PropertiesUtil.class,
+            "isPropertyInRoot", boolean.class, Set.class, NameIterator.class);
+    static final MethodDescriptor HS_NEW = MethodDescriptor.ofConstructor(HashSet.class);
+    static final MethodDescriptor HS_PUT = MethodDescriptor.ofMethod(HashSet.class, "add", boolean.class, Object.class);
+
     // todo: more space-efficient sorted map impl
     static final MethodDescriptor TM_NEW = MethodDescriptor.ofConstructor(TreeMap.class);
 
@@ -362,7 +370,6 @@ public static final class GenerateOperation implements AutoCloseable {
 
             clinit.invokeStaticMethod(PM_SET_RUNTIME_DEFAULT_PROFILE, clinit.load(ProfileManager.getActiveProfile()));
             clinitNameBuilder = clinit.newInstance(SB_NEW);
-            clinit.invokeVirtualMethod(SB_APPEND_STRING, clinitNameBuilder, clinit.load("quarkus"));
 
             // create the map for build time config source
             final ResultHandle buildTimeValues = clinit.newInstance(HM_NEW);
@@ -437,15 +444,12 @@ public static final class GenerateOperation implements AutoCloseable {
                 readBootstrapConfigNameBuilder = null;
             } else {
                 readBootstrapConfigNameBuilder = readBootstrapConfig.newInstance(SB_NEW);
-                readBootstrapConfig.invokeVirtualMethod(SB_APPEND_STRING, readBootstrapConfigNameBuilder,
-                        readBootstrapConfig.load("quarkus"));
             }
 
             // create readConfig
             readConfig = cc.getMethodCreator(C_READ_CONFIG);
             // the readConfig name builder
             readConfigNameBuilder = readConfig.newInstance(SB_NEW);
-            readConfig.invokeVirtualMethod(SB_APPEND_STRING, readConfigNameBuilder, readConfig.load("quarkus"));
 
             accessorFinder = new AccessorFinder();
         }
@@ -701,8 +705,7 @@ public void run() {
                 }
 
                 // specific actions based on config phase
-                String rootName = root.getRootName();
-                if (root.getConfigPhase() == ConfigPhase.BUILD_AND_RUN_TIME_FIXED) {
+                if (root.getConfigPhase() == BUILD_AND_RUN_TIME_FIXED) {
                     // config root field is volatile in dev mode, final otherwise; we initialize it from clinit, and readConfig in dev mode
                     cc.getFieldCreator(rootFieldDescriptor)
                             .setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC
@@ -720,19 +723,13 @@ public void run() {
                     clinit.writeStaticField(rootFieldDescriptor, instance);
                     instanceCache.put(rootFieldDescriptor, instance);
                     // eager init as appropriate
-                    if (!rootName.isEmpty()) {
-                        clinit.invokeVirtualMethod(SB_APPEND_CHAR, clinitNameBuilder, clinit.load('.'));
-                        clinit.invokeVirtualMethod(SB_APPEND_STRING, clinitNameBuilder, clinit.load(rootName));
-                    }
+                    clinit.invokeVirtualMethod(SB_APPEND_STRING, clinitNameBuilder, clinit.load(root.getName()));
                     clinit.invokeStaticMethod(initGroup, clinitConfig, clinitNameBuilder, instance);
                     clinit.invokeVirtualMethod(SB_SET_LENGTH, clinitNameBuilder, clInitOldLen);
                     if (devMode) {
                         instance = readConfig.readStaticField(rootFieldDescriptor);
-                        if (!rootName.isEmpty()) {
-                            readConfig.invokeVirtualMethod(SB_APPEND_CHAR, readConfigNameBuilder, readConfig.load('.'));
-                            readConfig.invokeVirtualMethod(SB_APPEND_STRING, readConfigNameBuilder,
-                                    readConfig.load(rootName));
-                        }
+                        readConfig.invokeVirtualMethod(SB_APPEND_STRING, readConfigNameBuilder,
+                                readConfig.load(root.getName()));
                         readConfig.invokeStaticMethod(initGroup, runTimeConfig, readConfigNameBuilder, instance);
                         readConfig.invokeVirtualMethod(SB_SET_LENGTH, readConfigNameBuilder, rcOldLen);
                     }
@@ -752,12 +749,8 @@ public void run() {
 
                         // assign instance to field
                         readBootstrapConfig.writeStaticField(rootFieldDescriptor, instance);
-                        if (!rootName.isEmpty()) {
-                            readBootstrapConfig.invokeVirtualMethod(SB_APPEND_CHAR, readBootstrapConfigNameBuilder,
-                                    readBootstrapConfig.load('.'));
-                            readBootstrapConfig.invokeVirtualMethod(SB_APPEND_STRING, readBootstrapConfigNameBuilder,
-                                    readBootstrapConfig.load(rootName));
-                        }
+                        readBootstrapConfig.invokeVirtualMethod(SB_APPEND_STRING, readBootstrapConfigNameBuilder,
+                                readBootstrapConfig.load(root.getName()));
                         readBootstrapConfig.invokeStaticMethod(initGroup, bootstrapConfig, readBootstrapConfigNameBuilder,
                                 instance);
                         readBootstrapConfig.invokeVirtualMethod(SB_SET_LENGTH, readBootstrapConfigNameBuilder, bcOldLen);
@@ -777,11 +770,7 @@ public void run() {
 
                     // assign instance to field
                     readConfig.writeStaticField(rootFieldDescriptor, instance);
-                    if (!rootName.isEmpty()) {
-                        readConfig.invokeVirtualMethod(SB_APPEND_CHAR, readConfigNameBuilder, readConfig.load('.'));
-                        readConfig.invokeVirtualMethod(SB_APPEND_STRING, readConfigNameBuilder,
-                                readConfig.load(rootName));
-                    }
+                    readConfig.invokeVirtualMethod(SB_APPEND_STRING, readConfigNameBuilder, readConfig.load(root.getName()));
                     readConfig.invokeStaticMethod(initGroup, runTimeConfig, readConfigNameBuilder, instance);
                     readConfig.invokeVirtualMethod(SB_SET_LENGTH, readConfigNameBuilder, rcOldLen);
                 } else {
@@ -791,23 +780,23 @@ public void run() {
             }
 
             // generate sweep for clinit
-            configSweepLoop(siParserBody, clinit, clinitConfig);
+            configSweepLoop(siParserBody, clinit, clinitConfig, getRegisteredRoots(BUILD_AND_RUN_TIME_FIXED));
 
             clinit.invokeStaticMethod(CD_UNKNOWN_PROPERTIES,
                     clinit.readStaticField(FieldDescriptor.of(cc.getClassName(), "unused", List.class)));
 
             if (devMode) {
-                configSweepLoop(siParserBody, readConfig, runTimeConfig);
+                configSweepLoop(siParserBody, readConfig, runTimeConfig, getRegisteredRoots(RUN_TIME));
             }
             // generate sweep for run time
-            configSweepLoop(rtParserBody, readConfig, runTimeConfig);
+            configSweepLoop(rtParserBody, readConfig, runTimeConfig, getRegisteredRoots(RUN_TIME));
 
             readConfig.invokeStaticMethod(CD_UNKNOWN_PROPERTIES_RT,
                     readConfig.readStaticField(FieldDescriptor.of(cc.getClassName(), "unusedRuntime", List.class)));
 
             if (bootstrapConfigSetupNeeded()) {
                 // generate sweep for bootstrap config
-                configSweepLoop(bsParserBody, readBootstrapConfig, bootstrapConfig);
+                configSweepLoop(bsParserBody, readBootstrapConfig, bootstrapConfig, getRegisteredRoots(BOOTSTRAP));
             }
 
             // generate ensure-initialized method
@@ -874,9 +863,17 @@ public void run() {
             generateDefaultValuesConfigSourceClass(buildTimeRunTimePatternMap, BTRTDVCS_CLASS_NAME);
         }
 
-        private static void configSweepLoop(MethodDescriptor parserBody, MethodCreator method, ResultHandle config) {
+        private void configSweepLoop(MethodDescriptor parserBody, MethodCreator method, ResultHandle config,
+                Set<String> registeredRoots) {
+            ResultHandle rootSet;
             ResultHandle nameSet;
             ResultHandle iterator;
+
+            rootSet = method.newInstance(HS_NEW);
+            for (String registeredRoot : registeredRoots) {
+                method.invokeVirtualMethod(HS_PUT, rootSet, method.load(registeredRoot));
+            }
+
             nameSet = method.invokeVirtualMethod(SRC_GET_PROPERTY_NAMES, config);
             iterator = method.invokeInterfaceMethod(ITRA_ITERATOR, nameSet);
 
@@ -890,10 +887,8 @@ private static void configSweepLoop(MethodDescriptor parserBody, MethodCreator m
                     // if (! keyIter.hasNext()) continue sweepLoop;
                     hasNext.ifNonZero(hasNext.invokeVirtualMethod(NI_HAS_NEXT, keyIter)).falseBranch().continueScope(sweepLoop);
                     // if (! keyIter.nextSegmentEquals("quarkus")) continue sweepLoop;
-                    hasNext.ifNonZero(hasNext.invokeVirtualMethod(NI_NEXT_EQUALS, keyIter, hasNext.load("quarkus")))
-                            .falseBranch().continueScope(sweepLoop);
-                    // keyIter.next(); // skip "quarkus"
-                    hasNext.invokeVirtualMethod(NI_NEXT, keyIter);
+                    hasNext.ifNonZero(hasNext.invokeStaticMethod(PU_IS_PROPERTY_IN_ROOT, rootSet, keyIter)).falseBranch()
+                            .continueScope(sweepLoop);
                     // parse(config, keyIter);
                     hasNext.invokeStaticMethod(parserBody, config, keyIter);
                     // continue sweepLoop;
@@ -902,6 +897,16 @@ private static void configSweepLoop(MethodDescriptor parserBody, MethodCreator m
             }
         }
 
+        private Set<String> getRegisteredRoots(ConfigPhase configPhase) {
+            Set<String> registeredRoots = new HashSet<>();
+            for (RootDefinition root : roots) {
+                if (root.getConfigPhase().equals(configPhase)) {
+                    registeredRoots.add(root.getPrefix());
+                }
+            }
+            return registeredRoots;
+        }
+
         private void installConfiguration(ResultHandle config, MethodCreator methodCreator) {
             // install config
             methodCreator.invokeStaticMethod(QCF_SET_CONFIG, config);
@@ -928,14 +933,8 @@ private void generateDefaultValuesConfigSourceClass(ConfigPatternMap<Container>
                         // there is at least one default value
                         final BranchResult if1 = mc.ifNonZero(mc.invokeVirtualMethod(NI_HAS_NEXT, keyIter));
                         try (BytecodeCreator true1 = if1.trueBranch()) {
-                            true1.invokeVirtualMethod(NI_NEXT, keyIter);
-                            final BranchResult if2 = true1
-                                    .ifNonZero(true1.invokeVirtualMethod(NI_PREVIOUS_EQUALS, keyIter, true1.load("quarkus")));
-                            try (BytecodeCreator true2 = if2.trueBranch()) {
-                                final ResultHandle result = true2.invokeVirtualMethod(
-                                        md, mc.getThis(), keyIter);
-                                true2.returnValue(result);
-                            }
+                            final ResultHandle result = true1.invokeVirtualMethod(md, mc.getThis(), keyIter);
+                            true1.returnValue(result);
                         }
                     }
 
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/definition/RootDefinition.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/definition/RootDefinition.java
index f8b8f9956488f..0a8c8c8559728 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/definition/RootDefinition.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/definition/RootDefinition.java
@@ -19,12 +19,14 @@
  *
  */
 public final class RootDefinition extends ClassDefinition {
+    private final String prefix;
     private final ConfigPhase configPhase;
     private final String rootName;
     private final FieldDescriptor descriptor;
 
     RootDefinition(final Builder builder) {
         super(builder);
+        this.prefix = builder.prefix;
         this.configPhase = builder.configPhase;
         String rootName = builder.rootName;
         final Class<?> configClass = getConfigurationClass();
@@ -76,6 +78,10 @@ public final class RootDefinition extends ClassDefinition {
         this.descriptor = FieldDescriptor.of(CONFIG_CLASS_NAME, String.join("", segments), configClass);
     }
 
+    public String getPrefix() {
+        return prefix;
+    }
+
     public ConfigPhase getConfigPhase() {
         return configPhase;
     }
@@ -84,17 +90,38 @@ public String getRootName() {
         return rootName;
     }
 
+    public String getName() {
+        if (prefix != null && !prefix.isEmpty()) {
+            if (rootName != null && !rootName.isEmpty()) {
+                return prefix + "." + rootName;
+            } else {
+                return prefix;
+            }
+        } else {
+            return rootName;
+        }
+    }
+
     public FieldDescriptor getDescriptor() {
         return descriptor;
     }
 
     public static final class Builder extends ClassDefinition.Builder {
+        private String prefix = "quarkus";
         private ConfigPhase configPhase = ConfigPhase.BUILD_TIME;
         private String rootName = ConfigItem.HYPHENATED_ELEMENT_NAME;
 
         public Builder() {
         }
 
+        public String getPrefix() {
+            return prefix;
+        }
+
+        public void setPrefix(final String prefix) {
+            this.prefix = prefix;
+        }
+
         public ConfigPhase getConfigPhase() {
             return configPhase;
         }
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/configuration/matching/PatternMapBuilder.java b/core/deployment/src/main/java/io/quarkus/deployment/configuration/matching/PatternMapBuilder.java
index d614f7a49caae..8d1c8a16e35cd 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/configuration/matching/PatternMapBuilder.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/configuration/matching/PatternMapBuilder.java
@@ -17,21 +17,18 @@ private PatternMapBuilder() {
     public static ConfigPatternMap<Container> makePatterns(List<RootDefinition> rootDefinitions) {
         ConfigPatternMap<Container> patternMap = new ConfigPatternMap<>();
         for (RootDefinition rootDefinition : rootDefinitions) {
-            final String rootName = rootDefinition.getRootName();
             ConfigPatternMap<Container> addTo = patternMap, child;
-            if (!rootName.isEmpty()) {
-                NameIterator ni = new NameIterator(rootName);
-                assert ni.hasNext();
-                do {
-                    final String seg = ni.getNextSegment();
-                    child = addTo.getChild(seg);
-                    ni.next();
-                    if (child == null) {
-                        addTo.addChild(seg, child = new ConfigPatternMap<>());
-                    }
-                    addTo = child;
-                } while (ni.hasNext());
-            }
+            NameIterator ni = new NameIterator(rootDefinition.getName());
+            assert ni.hasNext();
+            do {
+                final String seg = ni.getNextSegment();
+                child = addTo.getChild(seg);
+                ni.next();
+                if (child == null) {
+                    addTo.addChild(seg, child = new ConfigPatternMap<>());
+                }
+                addTo = child;
+            } while (ni.hasNext());
             addGroup(addTo, rootDefinition, null);
         }
         return patternMap;
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java
index a576fc64c7ad5..7df55f688507f 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigDescriptionBuildStep.java
@@ -48,49 +48,65 @@ List<ConfigDescriptionBuildItem> createConfigDescriptions(
         return ret;
     }
 
-    private void processConfig(ConfigPatternMap<Container> patterns, List<ConfigDescriptionBuildItem> ret,
+    private void processConfig(ConfigPatternMap<Container> patterns, List<ConfigDescriptionBuildItem> ret, Properties javadoc,
+            ConfigPhase configPhase) {
+        for (String childName : patterns.childNames()) {
+            ConfigPatternMap<Container> child = patterns.getChild(childName);
+            processConfigChild(childName, child, ret, javadoc, configPhase);
+        }
+    }
+
+    private void processConfigChild(String name, ConfigPatternMap<Container> patterns, List<ConfigDescriptionBuildItem> ret,
             Properties javadoc, ConfigPhase configPhase) {
 
-        patterns.forEach(new Consumer<Container>() {
-            @Override
-            public void accept(Container node) {
-                Field field = node.findField();
-                ConfigItem configItem = field.getAnnotation(ConfigItem.class);
-                final ConfigProperty configProperty = field.getAnnotation(ConfigProperty.class);
-                String defaultDefault;
-                final Class<?> valueClass = field.getType();
-
-                EffectiveConfigTypeAndValues effectiveConfigTypeAndValues = getTypeName(field);
-
-                if (valueClass == boolean.class) {
-                    defaultDefault = "false";
-                } else if (valueClass.isPrimitive() && valueClass != char.class) {
-                    defaultDefault = "0";
-                } else {
-                    defaultDefault = null;
-                }
-                String defVal = defaultDefault;
-                if (configItem != null) {
-                    final String itemDefVal = configItem.defaultValue();
-                    if (!itemDefVal.equals(ConfigItem.NO_DEFAULT)) {
-                        defVal = itemDefVal;
+        Iterable<String> childNames = patterns.childNames();
+        if (childNames.iterator().hasNext()) {
+            for (String childName : childNames) {
+                ConfigPatternMap<Container> child = patterns.getChild(childName);
+                processConfigChild(name + "." + childName, child, ret, javadoc, configPhase);
+            }
+        } else {
+            patterns.forEach(new Consumer<Container>() {
+                @Override
+                public void accept(Container node) {
+                    Field field = node.findField();
+                    ConfigItem configItem = field.getAnnotation(ConfigItem.class);
+                    final ConfigProperty configProperty = field.getAnnotation(ConfigProperty.class);
+                    String defaultDefault;
+                    final Class<?> valueClass = field.getType();
+
+                    EffectiveConfigTypeAndValues effectiveConfigTypeAndValues = getTypeName(field);
+
+                    if (valueClass == boolean.class) {
+                        defaultDefault = "false";
+                    } else if (valueClass.isPrimitive() && valueClass != char.class) {
+                        defaultDefault = "0";
+                    } else {
+                        defaultDefault = null;
                     }
-                } else if (configProperty != null) {
-                    final String propDefVal = configProperty.defaultValue();
-                    if (!propDefVal.equals(ConfigProperty.UNCONFIGURED_VALUE)) {
-                        defVal = propDefVal;
+                    String defVal = defaultDefault;
+                    if (configItem != null) {
+                        final String itemDefVal = configItem.defaultValue();
+                        if (!itemDefVal.equals(ConfigItem.NO_DEFAULT)) {
+                            defVal = itemDefVal;
+                        }
+                    } else if (configProperty != null) {
+                        final String propDefVal = configProperty.defaultValue();
+                        if (!propDefVal.equals(ConfigProperty.UNCONFIGURED_VALUE)) {
+                            defVal = propDefVal;
+                        }
                     }
+                    String javadocKey = field.getDeclaringClass().getName().replace('$', '.') + '.' + field.getName();
+                    ret.add(new ConfigDescriptionBuildItem(name,
+                            node.findEnclosingClass().getConfigurationClass(),
+                            defVal,
+                            javadoc.getProperty(javadocKey),
+                            effectiveConfigTypeAndValues.getTypeName(),
+                            effectiveConfigTypeAndValues.getAllowedValues(),
+                            configPhase));
                 }
-                String javadocKey = field.getDeclaringClass().getName().replace('$', '.') + '.' + field.getName();
-                ret.add(new ConfigDescriptionBuildItem("quarkus." + node.getPropertyName(),
-                        node.findEnclosingClass().getConfigurationClass(),
-                        defVal,
-                        javadoc.getProperty(javadocKey),
-                        effectiveConfigTypeAndValues.getTypeName(),
-                        effectiveConfigTypeAndValues.getAllowedValues(),
-                        configPhase));
-            }
-        });
+            });
+        }
     }
 
     private EffectiveConfigTypeAndValues getTypeName(Field field) {
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java
index 0eacb06801099..90675727b9619 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigGenerationBuildStep.java
@@ -147,8 +147,12 @@ private List<String> getAdditionalBootstrapConfigSourceProviders(
     }
 
     @BuildStep
-    public SuppressNonRuntimeConfigChangedWarningBuildItem ignoreQuarkusProfileChange() {
-        return new SuppressNonRuntimeConfigChangedWarningBuildItem("quarkus.profile");
+    public void suppressNonRuntimeConfigChanged(
+            BuildProducer<SuppressNonRuntimeConfigChangedWarningBuildItem> suppressNonRuntimeConfigChanged) {
+        suppressNonRuntimeConfigChanged.produce(new SuppressNonRuntimeConfigChangedWarningBuildItem("quarkus.profile"));
+        suppressNonRuntimeConfigChanged.produce(new SuppressNonRuntimeConfigChangedWarningBuildItem("quarkus.uuid"));
+        suppressNonRuntimeConfigChanged.produce(new SuppressNonRuntimeConfigChangedWarningBuildItem("quarkus.default-locale"));
+        suppressNonRuntimeConfigChanged.produce(new SuppressNonRuntimeConfigChangedWarningBuildItem("quarkus.locales"));
     }
 
     /**
@@ -174,7 +178,7 @@ public void checkForBuildTimeConfigChange(
                     root.getConfigPhase() == ConfigPhase.BUILD_TIME) {
 
                 Iterable<ClassDefinition.ClassMember> members = root.getMembers();
-                handleMembers(config, values, members, "quarkus." + root.getRootName() + ".", excludedConfigKeys);
+                handleMembers(config, values, members, root.getName() + ".", excludedConfigKeys);
             }
         }
         recorder.handleConfigChange(configurationConfig, values);
diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java
index f0cf97b161be1..86c83f3b5f519 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java
@@ -2,7 +2,7 @@
 
 import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeConfigGroupDocFileName;
 import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeConfigRootDocFileName;
-import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.deriveConfigRootName;
+import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getName;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -64,6 +64,7 @@ public void addConfigRoot(final PackageElement pkg, TypeElement clazz) {
             return;
         }
 
+        String prefix = Constants.QUARKUS;
         ConfigPhase configPhase = ConfigPhase.BUILD_TIME;
 
         for (AnnotationMirror annotationMirror : clazz.getAnnotationMirrors()) {
@@ -71,20 +72,21 @@ public void addConfigRoot(final PackageElement pkg, TypeElement clazz) {
             if (annotationName.equals(Constants.ANNOTATION_CONFIG_ROOT)) {
                 final Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = annotationMirror
                         .getElementValues();
-                String name = Constants.EMPTY;
+                String name = Constants.HYPHENATED_ELEMENT_NAME;
                 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : elementValues.entrySet()) {
                     final String key = entry.getKey().toString();
                     final String value = entry.getValue().getValue().toString();
                     if ("name()".equals(key)) {
-                        name = Constants.QUARKUS + Constants.DOT + value;
+                        name = value;
                     } else if ("phase()".equals(key)) {
                         configPhase = ConfigPhase.valueOf(value);
+                    } else if ("prefix()".equals(key)) {
+                        prefix = value;
                     }
                 }
 
-                if (name.isEmpty()) {
-                    name = deriveConfigRootName(clazz.getSimpleName().toString(), configPhase);
-                } else if (name.endsWith(Constants.DOT + Constants.PARENT)) {
+                name = getName(prefix, name, clazz.getSimpleName().toString(), configPhase);
+                if (name.endsWith(Constants.DOT + Constants.PARENT)) {
                     // take into account the root case which would contain characters that can't be used to create the final file
                     name = name.replace(Constants.DOT + Constants.PARENT, "");
                 }
diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java
index f4672bd4fa50d..7b4fc3fb99e45 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java
@@ -448,22 +448,39 @@ private static String typeSimpleName(TypeMirror typeMirror) {
         return type.substring(1 + type.lastIndexOf(Constants.DOT));
     }
 
-    static String deriveConfigRootName(String simpleClassName, ConfigPhase configPhase) {
+    static String getName(String prefix, String name, String simpleClassName, ConfigPhase configPhase) {
+        if (name.equals(Constants.HYPHENATED_ELEMENT_NAME)) {
+            return deriveConfigRootName(simpleClassName, prefix, configPhase);
+        }
+
+        if (!prefix.isEmpty()) {
+            if (!name.isEmpty()) {
+                return prefix + Constants.DOT + name;
+            } else {
+                return prefix;
+            }
+        } else {
+            return name;
+        }
+    }
+
+    static String deriveConfigRootName(String simpleClassName, String prefix, ConfigPhase configPhase) {
         String simpleNameInLowerCase = simpleClassName.toLowerCase();
         int length = simpleNameInLowerCase.length();
 
         if (simpleNameInLowerCase.endsWith(CONFIG.toLowerCase())) {
             String sanitized = simpleClassName.substring(0, length - CONFIG.length());
-            return deriveConfigRootName(sanitized, configPhase);
+            return deriveConfigRootName(sanitized, prefix, configPhase);
         } else if (simpleNameInLowerCase.endsWith(CONFIGURATION.toLowerCase())) {
             String sanitized = simpleClassName.substring(0, length - CONFIGURATION.length());
-            return deriveConfigRootName(sanitized, configPhase);
+            return deriveConfigRootName(sanitized, prefix, configPhase);
         } else if (simpleNameInLowerCase.endsWith(configPhase.getConfigSuffix().toLowerCase())) {
             String sanitized = simpleClassName.substring(0, length - configPhase.getConfigSuffix().length());
-            return deriveConfigRootName(sanitized, configPhase);
+            return deriveConfigRootName(sanitized, prefix, configPhase);
         }
 
-        return Constants.QUARKUS + Constants.DOT + hyphenate(simpleClassName);
+        return !prefix.isEmpty() ? prefix + Constants.DOT + hyphenate(simpleClassName)
+                : Constants.QUARKUS + Constants.DOT + hyphenate(simpleClassName);
     }
 
     /**
diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java
index 5266429f28734..46a201d6deb5f 100644
--- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java
+++ b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java
@@ -9,6 +9,7 @@
 import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeExtensionDocFileName;
 import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.deriveConfigRootName;
 import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getJavaDocSiteLink;
+import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getName;
 import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.normalizeDurationValue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
@@ -317,43 +318,90 @@ public void shouldDeepAppendConfigSectionConfigItemsIntoExistingConfigItemsOfCon
         assertEquals(configItem, deepSection.getConfigDocItems().get(1));
     }
 
+    @Test
+    void getNameTest() {
+        String prefix = Constants.QUARKUS;
+        String name = Constants.HYPHENATED_ELEMENT_NAME;
+        String simpleClassName = "MyConfig";
+        String actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME);
+        assertEquals("quarkus.my", actual);
+
+        prefix = "my.prefix";
+        name = "";
+        simpleClassName = "MyPrefix";
+        actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME);
+        assertEquals("my.prefix", actual);
+
+        prefix = "";
+        name = "my.prefix";
+        simpleClassName = "MyPrefix";
+        actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME);
+        assertEquals("my.prefix", actual);
+
+        prefix = "my";
+        name = "prefix";
+        simpleClassName = "MyPrefix";
+        actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME);
+        assertEquals("my.prefix", actual);
+
+        prefix = Constants.QUARKUS;
+        name = "prefix";
+        simpleClassName = "SomethingElse";
+        actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME);
+        assertEquals("quarkus.prefix", actual);
+
+        prefix = "";
+        name = Constants.HYPHENATED_ELEMENT_NAME;
+        simpleClassName = "SomethingElse";
+        actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME);
+        assertEquals("quarkus.something-else", actual);
+    }
+
     @Test
     public void derivingConfigRootNameTestCase() {
         // should hyphenate class name
         String simpleClassName = "RootName";
-        String actual = deriveConfigRootName(simpleClassName, ConfigPhase.RUN_TIME);
+        String actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME);
         assertEquals("quarkus.root-name", actual);
 
         // should hyphenate class name after removing Config(uration) suffix
         simpleClassName = "RootNameConfig";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.BUILD_TIME);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_TIME);
         assertEquals("quarkus.root-name", actual);
 
         simpleClassName = "RootNameConfiguration";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.BUILD_AND_RUN_TIME_FIXED);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_AND_RUN_TIME_FIXED);
         assertEquals("quarkus.root-name", actual);
 
         // should hyphenate class name after removing RunTimeConfig(uration) suffix
         simpleClassName = "RootNameRunTimeConfig";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.RUN_TIME);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME);
         assertEquals("quarkus.root-name", actual);
 
         simpleClassName = "RootNameRuntimeConfig";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.RUN_TIME);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME);
         assertEquals("quarkus.root-name", actual);
 
         simpleClassName = "RootNameRunTimeConfiguration";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.RUN_TIME);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME);
         assertEquals("quarkus.root-name", actual);
 
         // should hyphenate class name after removing BuildTimeConfig(uration) suffix
         simpleClassName = "RootNameBuildTimeConfig";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.BUILD_AND_RUN_TIME_FIXED);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_AND_RUN_TIME_FIXED);
         assertEquals("quarkus.root-name", actual);
 
         simpleClassName = "RootNameBuildTimeConfiguration";
-        actual = deriveConfigRootName(simpleClassName, ConfigPhase.BUILD_TIME);
+        actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_TIME);
         assertEquals("quarkus.root-name", actual);
+
+        simpleClassName = "RootName";
+        actual = deriveConfigRootName(simpleClassName, "prefix", ConfigPhase.RUN_TIME);
+        assertEquals("prefix.root-name", actual);
+
+        simpleClassName = "RootName";
+        actual = deriveConfigRootName(simpleClassName, "my.prefix", ConfigPhase.RUN_TIME);
+        assertEquals("my.prefix.root-name", actual);
     }
 
     @Test
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigRoot.java b/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigRoot.java
index a04b6fb81d12d..5124cb4d812ad 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigRoot.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/annotations/ConfigRoot.java
@@ -17,6 +17,13 @@
 @Target(TYPE)
 @Documented
 public @interface ConfigRoot {
+    /**
+     * Determine the prefix key of the configuration root.
+     *
+     * @return the prefix key name
+     */
+    String prefix() default "quarkus";
+
     /**
      * Determine the phase of this configuration root.
      *
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
index c9d2c35e3088c..315ebae2d7c17 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ConfigUtils.java
@@ -11,18 +11,16 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.OptionalInt;
 import java.util.Set;
 import java.util.SortedSet;
-import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.UUID;
-import java.util.function.BiConsumer;
 import java.util.function.IntFunction;
 
 import org.eclipse.microprofile.config.ConfigProvider;
@@ -223,7 +221,7 @@ static class BuildTimeEnvConfigSource extends EnvConfigSource {
 
         @Override
         public Set<String> getPropertyNames() {
-            return new HashSet<>();
+            return Collections.emptySet();
         }
 
         @Override
@@ -257,28 +255,18 @@ public String getName() {
 
     /**
      * We only want to include properties in the quarkus namespace.
+     *
+     * We removed the filter on the quarkus namespace due to the any prefix support for ConfigRoot. Filtering is now
+     * done in io.quarkus.deployment.configuration.BuildTimeConfigurationReader.ReadOperation#getAllProperties.
      */
     static class BuildTimeSysPropConfigSource extends SysPropConfigSource {
-        public Map<String, String> getProperties() {
-            BuildTimeSysPropMapProducer buildTimeSysPropMapProducer = new BuildTimeSysPropMapProducer();
-            System.getProperties().forEach(buildTimeSysPropMapProducer);
-            return buildTimeSysPropMapProducer.output;
-        }
-
         public String getName() {
             return "System properties";
         }
-    }
-
-    private static class BuildTimeSysPropMapProducer implements BiConsumer<Object, Object> {
-        final Map<String, String> output = new TreeMap<>();
 
         @Override
-        public void accept(Object k, Object v) {
-            String key = (String) k;
-            if (key.startsWith("quarkus.")) {
-                output.put(key, v.toString());
-            }
+        public Set<String> getPropertyNames() {
+            return Collections.emptySet();
         }
     }
 }
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/PropertiesUtil.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/PropertiesUtil.java
new file mode 100644
index 0000000000000..4af3b4e9e276c
--- /dev/null
+++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/PropertiesUtil.java
@@ -0,0 +1,50 @@
+package io.quarkus.runtime.configuration;
+
+import java.util.Set;
+
+public class PropertiesUtil {
+    private PropertiesUtil() {
+    }
+
+    public static boolean isPropertyInRoot(Set<String> roots, NameIterator propertyName) {
+        for (String root : roots) {
+            // match everything
+            if (root.length() == 0) {
+                return true;
+            }
+
+            // A sub property from a namespace is always bigger in length
+            if (propertyName.getName().length() <= root.length()) {
+                continue;
+            }
+
+            final NameIterator rootNi = new NameIterator(root);
+            // compare segments
+            while (rootNi.hasNext()) {
+                String segment = rootNi.getNextSegment();
+                if (!propertyName.hasNext()) {
+                    propertyName.goToStart();
+                    break;
+                }
+
+                final String nextSegment = propertyName.getNextSegment();
+                if (!segment.equals(nextSegment)) {
+                    propertyName.goToStart();
+                    break;
+                }
+
+                rootNi.next();
+                propertyName.next();
+
+                // root has no more segments and we reached this far so everything matched.
+                // on top, property still has more segments to do the mapping.
+                if (!rootNi.hasNext() && propertyName.hasNext()) {
+                    propertyName.goToStart();
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/PrefixConfigTestProcessor.java b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/PrefixConfigTestProcessor.java
new file mode 100644
index 0000000000000..5d733d5c9a24f
--- /dev/null
+++ b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/PrefixConfigTestProcessor.java
@@ -0,0 +1,32 @@
+package io.quarkus.extest.deployment;
+
+import java.util.List;
+
+import io.quarkus.arc.deployment.ConfigPropertyBuildItem;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.ConfigDescriptionBuildItem;
+import io.quarkus.extest.runtime.config.PrefixBuildTimeConfig;
+import io.quarkus.extest.runtime.config.PrefixConfig;
+
+public class PrefixConfigTestProcessor {
+    @BuildStep
+    void validateBuildTime(BuildProducer<ConfigPropertyBuildItem> configProperties,
+            PrefixBuildTimeConfig prefixBuildTimeConfig) {
+        assert prefixBuildTimeConfig.prop.equals("1234");
+        assert prefixBuildTimeConfig.map.get("prop").equals("1234");
+    }
+
+    @BuildStep
+    void validateRuntime(BuildProducer<ConfigPropertyBuildItem> configProperties,
+            List<ConfigDescriptionBuildItem> configDescriptionBuildItems,
+            PrefixConfig prefixConfig) {
+        assert prefixConfig.prop.equals("1234");
+        assert prefixConfig.map.get("prop").equals("1234");
+        assert prefixConfig.nested.nestedValue.equals("nested-1234");
+        assert prefixConfig.nested.oov.getPart1().equals("nested-1234");
+        assert prefixConfig.nested.oov.getPart2().equals("nested-5678");
+        assert configDescriptionBuildItems.stream().map(ConfigDescriptionBuildItem::getPropertyName)
+                .anyMatch("my.prefix.prop"::equals);
+    }
+}
diff --git a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
index 7c2aa916918cd..964b48a7f560c 100644
--- a/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
+++ b/core/test-extension/deployment/src/main/java/io/quarkus/extest/deployment/TestProcessor.java
@@ -60,14 +60,17 @@
 import io.quarkus.extest.runtime.TestRecorder;
 import io.quarkus.extest.runtime.beans.CommandServlet;
 import io.quarkus.extest.runtime.beans.PublicKeyProducer;
+import io.quarkus.extest.runtime.config.AnotherPrefixConfig;
 import io.quarkus.extest.runtime.config.FooRuntimeConfig;
 import io.quarkus.extest.runtime.config.ObjectOfValue;
 import io.quarkus.extest.runtime.config.ObjectValueOf;
+import io.quarkus.extest.runtime.config.PrefixConfig;
 import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
 import io.quarkus.extest.runtime.config.TestBuildTimeConfig;
 import io.quarkus.extest.runtime.config.TestConfigRoot;
 import io.quarkus.extest.runtime.config.TestRunTimeConfig;
 import io.quarkus.extest.runtime.config.XmlConfig;
+import io.quarkus.extest.runtime.config.named.PrefixNamedConfig;
 import io.quarkus.extest.runtime.logging.AdditionalLogHandlerValueFactory;
 import io.quarkus.extest.runtime.runtimeinitializedpackage.RuntimeInitializedClass;
 import io.quarkus.extest.runtime.subst.DSAPublicKeyObjectSubstitution;
@@ -383,11 +386,13 @@ void scanForBeans(TestRecorder recorder, BeanArchiveIndexBuildItem beanArchiveIn
     @Record(RUNTIME_INIT)
     void configureBeans(TestRecorder recorder, List<TestBeanBuildItem> testBeans,
             BeanContainerBuildItem beanContainer,
-            TestRunTimeConfig runTimeConfig, FooRuntimeConfig fooRuntimeConfig) {
+            TestRunTimeConfig runTimeConfig, FooRuntimeConfig fooRuntimeConfig, PrefixConfig prefixConfig,
+            PrefixNamedConfig prefixNamedConfig,
+            AnotherPrefixConfig anotherPrefixConfig) {
         for (TestBeanBuildItem testBeanBuildItem : testBeans) {
             Class<IConfigConsumer> beanClass = testBeanBuildItem.getConfigConsumer();
             recorder.configureBeans(beanContainer.getValue(), beanClass, buildAndRunTimeConfig, runTimeConfig,
-                    fooRuntimeConfig);
+                    fooRuntimeConfig, prefixConfig, prefixNamedConfig, anotherPrefixConfig);
         }
     }
 
diff --git a/core/test-extension/deployment/src/main/resources/application.properties b/core/test-extension/deployment/src/main/resources/application.properties
index 2786b4c2b8c1b..5826f053699c2 100644
--- a/core/test-extension/deployment/src/main/resources/application.properties
+++ b/core/test-extension/deployment/src/main/resources/application.properties
@@ -151,3 +151,20 @@ quarkus.arc.unremovable-types[0]=foo
 
 ### Do not record env values in build time
 bt.do.not.record=properties
+
+### prefix
+my.prefix.prop=1234
+my.prefix.map.prop=1234
+my.prefix.nested.nested-value=nested-1234
+my.prefix.nested.oov=nested-1234+nested-5678
+my.prefix.named.prop=1234
+my.prefix.named.map.prop=1234
+my.prefix.named.nested.nested-value=nested-1234
+my.prefix.named.nested.oov=nested-1234+nested-5678
+
+my.prefix.bt.prop=1234
+my.prefix.bt.nested.nested-value=nested-1234
+my.prefix.bt.nested.oov=nested-1234+nested-5678
+
+another.another-prefix.prop=5678
+another.another-prefix.map.prop=5678
diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBean.java b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBean.java
index b5c34882e94a6..50f29b7b7e287 100644
--- a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBean.java
+++ b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBean.java
@@ -1,14 +1,13 @@
 package io.quarkus.extest;
 
-import javax.enterprise.event.Observes;
-
 import io.quarkus.extest.runtime.IConfigConsumer;
 import io.quarkus.extest.runtime.TestAnnotation;
+import io.quarkus.extest.runtime.config.AnotherPrefixConfig;
 import io.quarkus.extest.runtime.config.FooRuntimeConfig;
+import io.quarkus.extest.runtime.config.PrefixConfig;
 import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
 import io.quarkus.extest.runtime.config.TestRunTimeConfig;
-import io.quarkus.runtime.ShutdownEvent;
-import io.quarkus.runtime.StartupEvent;
+import io.quarkus.extest.runtime.config.named.PrefixNamedConfig;
 
 /**
  * A sample bean
@@ -18,10 +17,9 @@ public class ConfiguredBean implements IConfigConsumer {
     volatile TestRunTimeConfig runTimeConfig;
     volatile TestBuildAndRunTimeConfig buildTimeConfig;
     volatile FooRuntimeConfig fooRuntimeConfig;
-
-    public ConfiguredBean() {
-        System.out.printf("ConfiguredBean.ctor, %s%n", super.toString());
-    }
+    volatile PrefixConfig prefixConfig;
+    volatile PrefixNamedConfig prefixNamedConfig;
+    volatile AnotherPrefixConfig anotherPrefixConfig;
 
     /**
      * Called by runtime with the runtime config object
@@ -30,25 +28,14 @@ public ConfiguredBean() {
      */
     @Override
     public void loadConfig(TestBuildAndRunTimeConfig buildTimeConfig, TestRunTimeConfig runTimeConfig,
-            FooRuntimeConfig fooRuntimeConfig) {
-        System.out.printf("loadConfig, buildTimeConfig=%s, runTimeConfig=%s, fooRuntimeConfig=%s%n", buildTimeConfig,
-                runTimeConfig, fooRuntimeConfig);
+            FooRuntimeConfig fooRuntimeConfig, PrefixConfig prefixConfig, PrefixNamedConfig prefixNamedConfig,
+            AnotherPrefixConfig anotherPrefixConfig) {
         this.buildTimeConfig = buildTimeConfig;
         this.runTimeConfig = runTimeConfig;
         this.fooRuntimeConfig = fooRuntimeConfig;
-    }
-
-    /**
-     * Called when the runtime has started
-     * 
-     * @param event
-     */
-    void onStart(@Observes StartupEvent event) {
-        System.out.printf("onStart, event=%s%n", event);
-    }
-
-    void onStop(@Observes ShutdownEvent event) {
-        System.out.printf("onStop, event=%s%n", event);
+        this.prefixConfig = prefixConfig;
+        this.prefixNamedConfig = prefixNamedConfig;
+        this.anotherPrefixConfig = anotherPrefixConfig;
     }
 
     public TestRunTimeConfig getRunTimeConfig() {
@@ -63,8 +50,15 @@ public FooRuntimeConfig getFooRuntimeConfig() {
         return fooRuntimeConfig;
     }
 
-    @Override
-    public String toString() {
-        return "ConfiguredBean{runTimeConfig=" + runTimeConfig + '}';
+    public PrefixConfig getPrefixConfig() {
+        return prefixConfig;
+    }
+
+    public PrefixNamedConfig getPrefixNamedConfig() {
+        return prefixNamedConfig;
+    }
+
+    public AnotherPrefixConfig getAnotherPrefixConfig() {
+        return anotherPrefixConfig;
     }
 }
diff --git a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java
index ddb88de43866a..1e5d7277733fb 100644
--- a/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java
+++ b/core/test-extension/deployment/src/test/java/io/quarkus/extest/ConfiguredBeanTest.java
@@ -2,7 +2,10 @@
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
@@ -28,13 +31,16 @@
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import io.quarkus.extest.runtime.config.AnotherPrefixConfig;
 import io.quarkus.extest.runtime.config.MyEnum;
 import io.quarkus.extest.runtime.config.NestedConfig;
 import io.quarkus.extest.runtime.config.ObjectOfValue;
 import io.quarkus.extest.runtime.config.ObjectValueOf;
 import io.quarkus.extest.runtime.config.OverrideBuildTimeConfigSource;
+import io.quarkus.extest.runtime.config.PrefixConfig;
 import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
 import io.quarkus.extest.runtime.config.TestRunTimeConfig;
+import io.quarkus.extest.runtime.config.named.PrefixNamedConfig;
 import io.quarkus.test.QuarkusUnitTest;
 import io.restassured.RestAssured;
 
@@ -359,4 +365,39 @@ public void testProfileDefaultValuesSource() {
         assertEquals("1234", defaultValues.getValue("%test.my.prop"));
         assertEquals("1234", config.getValue("my.prop", String.class));
     }
+
+    @Test
+    void prefixConfig() {
+        PrefixConfig prefixConfig = configuredBean.getPrefixConfig();
+        assertNotNull(prefixConfig);
+        assertEquals("1234", prefixConfig.prop);
+        assertEquals("1234", prefixConfig.map.get("prop"));
+        assertEquals("nested-1234", prefixConfig.nested.nestedValue);
+        assertEquals("nested-1234", prefixConfig.nested.oov.getPart1());
+        assertEquals("nested-5678", prefixConfig.nested.oov.getPart2());
+
+        PrefixNamedConfig prefixNamedConfig = configuredBean.getPrefixNamedConfig();
+        assertNotNull(prefixNamedConfig);
+        assertEquals("1234", prefixNamedConfig.prop);
+        assertEquals("1234", prefixNamedConfig.map.get("prop"));
+        assertEquals("nested-1234", prefixNamedConfig.nested.nestedValue);
+        assertEquals("nested-1234", prefixNamedConfig.nested.oov.getPart1());
+        assertEquals("nested-5678", prefixNamedConfig.nested.oov.getPart2());
+
+        AnotherPrefixConfig anotherPrefixConfig = configuredBean.getAnotherPrefixConfig();
+        assertNotNull(anotherPrefixConfig);
+        assertEquals("5678", anotherPrefixConfig.prop);
+        assertEquals("5678", anotherPrefixConfig.map.get("prop"));
+
+        ConfigSource defaultValues = null;
+        for (ConfigSource configSource : config.getConfigSources()) {
+            if (configSource.getName().contains("PropertiesConfigSource[source=Specified default values]")) {
+                defaultValues = configSource;
+                break;
+            }
+        }
+        assertNotNull(defaultValues);
+        // java.version should not be recorded
+        assertFalse(defaultValues.getPropertyNames().contains("java.version"));
+    }
 }
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/IConfigConsumer.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/IConfigConsumer.java
index 7af418953384c..fa04b5d36543a 100644
--- a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/IConfigConsumer.java
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/IConfigConsumer.java
@@ -1,13 +1,17 @@
 package io.quarkus.extest.runtime;
 
+import io.quarkus.extest.runtime.config.AnotherPrefixConfig;
 import io.quarkus.extest.runtime.config.FooRuntimeConfig;
+import io.quarkus.extest.runtime.config.PrefixConfig;
 import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
 import io.quarkus.extest.runtime.config.TestRunTimeConfig;
+import io.quarkus.extest.runtime.config.named.PrefixNamedConfig;
 
 /**
  * Interface used to pass the runtime configuration to an application bean for validation
  */
 public interface IConfigConsumer {
     void loadConfig(TestBuildAndRunTimeConfig buildTimeConfig, TestRunTimeConfig runTimeConfig,
-            FooRuntimeConfig fooRuntimeConfig);
+            FooRuntimeConfig fooRuntimeConfig, PrefixConfig prefixConfig, PrefixNamedConfig prefixNamedConfig,
+            AnotherPrefixConfig anotherPrefixConfig);
 }
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java
index 412c2ebb9aa01..5984d6b55e2ae 100644
--- a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/TestRecorder.java
@@ -8,10 +8,13 @@
 
 import io.quarkus.arc.runtime.BeanContainer;
 import io.quarkus.extest.runtime.beans.PublicKeyProducer;
+import io.quarkus.extest.runtime.config.AnotherPrefixConfig;
 import io.quarkus.extest.runtime.config.FooRuntimeConfig;
+import io.quarkus.extest.runtime.config.PrefixConfig;
 import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
 import io.quarkus.extest.runtime.config.TestRunTimeConfig;
 import io.quarkus.extest.runtime.config.XmlConfig;
+import io.quarkus.extest.runtime.config.named.PrefixNamedConfig;
 import io.quarkus.runtime.RuntimeValue;
 import io.quarkus.runtime.ShutdownContext;
 import io.quarkus.runtime.annotations.Recorder;
@@ -31,14 +34,18 @@ public class TestRecorder {
      * @param beanClass - IConfigConsumer
      * @param buildTimeConfig - the extension TestBuildAndRunTimeConfig
      * @param runTimeConfig - the extension TestRunTimeConfig
-     * @see IConfigConsumer#loadConfig(TestBuildAndRunTimeConfig, TestRunTimeConfig)
+     * @see IConfigConsumer#loadConfig(TestBuildAndRunTimeConfig, TestRunTimeConfig, FooRuntimeConfig, PrefixConfig,
+     *      PrefixNamedConfig, AnotherPrefixConfig)
      */
     public void configureBeans(BeanContainer beanContainer, Class<IConfigConsumer> beanClass,
             TestBuildAndRunTimeConfig buildTimeConfig,
-            TestRunTimeConfig runTimeConfig, FooRuntimeConfig fooRuntimeConfig) {
+            TestRunTimeConfig runTimeConfig, FooRuntimeConfig fooRuntimeConfig, PrefixConfig prefixConfig,
+            PrefixNamedConfig prefixNamedConfig,
+            AnotherPrefixConfig anotherPrefixConfig) {
         log.infof("Begin BeanContainerListener callback\n");
         IConfigConsumer instance = beanContainer.instance(beanClass);
-        instance.loadConfig(buildTimeConfig, runTimeConfig, fooRuntimeConfig);
+        instance.loadConfig(buildTimeConfig, runTimeConfig, fooRuntimeConfig, prefixConfig, prefixNamedConfig,
+                anotherPrefixConfig);
         log.infof("configureBeans, instance=%s\n", instance);
     }
 
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/AnotherPrefixConfig.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/AnotherPrefixConfig.java
new file mode 100644
index 0000000000000..478c285b8c8d0
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/AnotherPrefixConfig.java
@@ -0,0 +1,17 @@
+package io.quarkus.extest.runtime.config;
+
+import java.util.Map;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(prefix = "another", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
+public class AnotherPrefixConfig {
+    /** */
+    @ConfigItem
+    public String prop;
+    /** */
+    @ConfigItem
+    public Map<String, String> map;
+}
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/PrefixBuildTimeConfig.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/PrefixBuildTimeConfig.java
new file mode 100644
index 0000000000000..a7da5173518ea
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/PrefixBuildTimeConfig.java
@@ -0,0 +1,24 @@
+package io.quarkus.extest.runtime.config;
+
+import java.util.Map;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(prefix = "my.prefix.bt", phase = ConfigPhase.BUILD_TIME, name = "")
+public class PrefixBuildTimeConfig {
+    /** */
+    @ConfigItem
+    public String prop;
+    /** */
+    @ConfigItem
+    public Map<String, String> map;
+    /** */
+    @ConfigItem
+    public NestedConfig nested;
+
+    static {
+        System.setProperty("my.prefix.bt.map.prop", "1234");
+    }
+}
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/PrefixConfig.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/PrefixConfig.java
new file mode 100644
index 0000000000000..8cb25b5d241a3
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/PrefixConfig.java
@@ -0,0 +1,20 @@
+package io.quarkus.extest.runtime.config;
+
+import java.util.Map;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(prefix = "my.prefix", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED, name = "")
+public class PrefixConfig {
+    /** */
+    @ConfigItem
+    public String prop;
+    /** */
+    @ConfigItem
+    public Map<String, String> map;
+    /** */
+    @ConfigItem
+    public NestedConfig nested;
+}
diff --git a/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/named/PrefixNamedConfig.java b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/named/PrefixNamedConfig.java
new file mode 100644
index 0000000000000..bca9df5720ea2
--- /dev/null
+++ b/core/test-extension/runtime/src/main/java/io/quarkus/extest/runtime/config/named/PrefixNamedConfig.java
@@ -0,0 +1,21 @@
+package io.quarkus.extest.runtime.config.named;
+
+import java.util.Map;
+
+import io.quarkus.extest.runtime.config.NestedConfig;
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(prefix = "my.prefix", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED, name = "named")
+public class PrefixNamedConfig {
+    /** */
+    @ConfigItem
+    public String prop;
+    /** */
+    @ConfigItem
+    public Map<String, String> map;
+    /** */
+    @ConfigItem
+    public NestedConfig nested;
+}
diff --git a/integration-tests/test-extension/src/main/java/io/quarkus/it/extension/NativeBean.java b/integration-tests/test-extension/src/main/java/io/quarkus/it/extension/NativeBean.java
deleted file mode 100644
index 61f11ff16246e..0000000000000
--- a/integration-tests/test-extension/src/main/java/io/quarkus/it/extension/NativeBean.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package io.quarkus.it.extension;
-
-import javax.enterprise.event.Observes;
-
-import io.quarkus.extest.runtime.IConfigConsumer;
-import io.quarkus.extest.runtime.TestAnnotation;
-import io.quarkus.extest.runtime.config.FooRuntimeConfig;
-import io.quarkus.extest.runtime.config.TestBuildAndRunTimeConfig;
-import io.quarkus.extest.runtime.config.TestRunTimeConfig;
-import io.quarkus.runtime.ShutdownEvent;
-import io.quarkus.runtime.StartupEvent;
-
-@TestAnnotation
-public class NativeBean implements IConfigConsumer {
-    volatile TestRunTimeConfig runTimeConfig;
-    volatile TestBuildAndRunTimeConfig buildTimeConfig;
-    volatile FooRuntimeConfig fooRuntimeConfig;
-
-    public NativeBean() {
-        System.out.printf("NativeBean.ctor, %s%n", super.toString());
-    }
-
-    /**
-     * Called by runtime with the runtime config object
-     *
-     * @param runTimeConfig
-     */
-    @Override
-    public void loadConfig(TestBuildAndRunTimeConfig buildTimeConfig, TestRunTimeConfig runTimeConfig,
-            FooRuntimeConfig fooRuntimeConfig) {
-        System.out.printf("loadConfig, buildTimeConfig=%s, runTimeConfig=%s, fooRuntimeConfig=%s%n", buildTimeConfig,
-                runTimeConfig, fooRuntimeConfig);
-        this.buildTimeConfig = buildTimeConfig;
-        this.runTimeConfig = runTimeConfig;
-        this.fooRuntimeConfig = fooRuntimeConfig;
-    }
-
-    /**
-     * Called when the runtime has started
-     *
-     * @param event
-     */
-    void onStart(@Observes StartupEvent event) {
-        System.out.printf("onStart, event=%s%n", event);
-    }
-
-    void onStop(@Observes ShutdownEvent event) {
-        System.out.printf("onStop, event=%s%n", event);
-    }
-
-}