diff --git a/implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilder.java b/implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilder.java
new file mode 100644
index 000000000..2ec0e593b
--- /dev/null
+++ b/implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilder.java
@@ -0,0 +1,320 @@
+package io.smallrye.config;
+
+import java.io.Serializable;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * A builder which can produce instances of a configuration interface.
+ *
+ * Objects which are produced by this API will contain values for every property found on the configuration
+ * interface or its supertypes.
+ * If no value is given for a property, its default value is used.
+ * If a required property has no default value, then an exception will be thrown when {@link #build} is called.
+ * The returned object instance is immutable and has a stable {@code equals} and {@code hashCode} method.
+ * If the runtime is Java 16 or later, the returned object may be a {@code Record}.
+ *
+ * To provide a value for a property, use a method reference to indicate which property the value should be associated
+ * with.
+ * For example,
+ *
+ *
+ *
+ * @param the configuration interface type
+ */
+public interface ConfigInstanceBuilder {
+ /**
+ * {@return the configuration interface (not null)}
+ */
+ Class configurationInterface();
+
+ /**
+ * Set a property on the configuration object to an object value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the value type
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null}
+ * or if the value is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder with(F getter, T value);
+
+ /**
+ * Set a property on the configuration object to an integer value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder with(F getter, int value);
+
+ /**
+ * Set a property on the configuration object to an integer value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder with(F getter, long value);
+
+ /**
+ * Set a property on the configuration object to a floating-point value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder with(F getter, double value);
+
+ /**
+ * Set a property on the configuration object to a boolean value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder with(F getter, boolean value);
+
+ /**
+ * Set an optional property on the configuration object to an object value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @param the value type
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ * or the value is {@code null}
+ */
+ default > & Serializable> ConfigInstanceBuilder withOptional(F getter,
+ T value) {
+ return with(getter, Optional.of(value));
+ }
+
+ /**
+ * Set an optional property on the configuration object to an integer value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ default & Serializable> ConfigInstanceBuilder withOptional(F getter,
+ int value) {
+ return with(getter, OptionalInt.of(value));
+ }
+
+ /**
+ * Set an optional property on the configuration object to an integer value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ default & Serializable> ConfigInstanceBuilder withOptional(F getter,
+ long value) {
+ return with(getter, OptionalLong.of(value));
+ }
+
+ /**
+ * Set an optional property on the configuration object to a floating-point value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ default & Serializable> ConfigInstanceBuilder withOptional(F getter,
+ double value) {
+ return with(getter, OptionalDouble.of(value));
+ }
+
+ /**
+ * Set an optional property on the configuration object to a boolean value.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ default > & Serializable> ConfigInstanceBuilder withOptional(F getter,
+ boolean value) {
+ return with(getter, Optional.of(Boolean.valueOf(value)));
+ }
+
+ /**
+ * Set a property to its default value (if any).
+ *
+ * @param getter the property to modify (must not be {@code null})
+ * @param the value type
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder withDefaultFor(F getter);
+
+ /**
+ * Set a property to its default value (if any).
+ *
+ * @param getter the property to modify (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder withDefaultFor(F getter);
+
+ /**
+ * Set a property to its default value (if any).
+ *
+ * @param getter the property to modify (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder withDefaultFor(F getter);
+
+ /**
+ * Set a property to its default value (if any).
+ *
+ * @param getter the property to modify (must not be {@code null})
+ * @param the accessor type
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the getter is {@code null}
+ */
+ & Serializable> ConfigInstanceBuilder withDefaultFor(F getter);
+
+ /**
+ * Set a property on the configuration object to a string value.
+ * The value set on the property will be the result of conversion of the string
+ * using the property's converter.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null},
+ * or if the value is {@code null},
+ * or if the value was rejected by the converter
+ */
+ & Serializable> ConfigInstanceBuilder withString(F getter, String value);
+
+ /**
+ * Set a property on the configuration object to a string value.
+ * The value set on the property will be the result of conversion of the string
+ * using the property's converter.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null},
+ * or if the value is {@code null},
+ * or if the value was rejected by the converter
+ */
+ & Serializable> ConfigInstanceBuilder withString(F getter, String value);
+
+ /**
+ * Set a property on the configuration object to a string value.
+ * The value set on the property will be the result of conversion of the string
+ * using the property's converter.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null},
+ * or if the value is {@code null},
+ * or if the value was rejected by the converter
+ */
+ & Serializable> ConfigInstanceBuilder withString(F getter, String value);
+
+ /**
+ * Set a property on the configuration object to a string value.
+ * The value set on the property will be the result of conversion of the string
+ * using the property's converter.
+ *
+ * @param getter the property accessor (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @param the accessor type
+ * @throws IllegalArgumentException if the getter is {@code null},
+ * or if the value is {@code null},
+ * or if the value was rejected by the converter
+ */
+ & Serializable> ConfigInstanceBuilder withString(F getter, String value);
+
+ /**
+ * Set a property on the configuration object to a string value, using the property's
+ * declaring class and name to identify the property to set.
+ * The value set on the property will be the result of conversion of the string
+ * using the property's converter.
+ *
+ * @param propertyClass the declaring class of the property to set (must not be {@code null})
+ * @param propertyName the name of the property to set (must not be {@code null})
+ * @param value the value to set (must not be {@code null})
+ * @return this builder (not {@code null})
+ * @throws IllegalArgumentException if the property class or name is {@code null},
+ * or if the value is {@code null},
+ * or if the value was rejected by the converter,
+ * or if no property matches the given name and declaring class
+ */
+ ConfigInstanceBuilder withString(Class super I> propertyClass, String propertyName, String value);
+
+ /**
+ * Build the configuration instance.
+ *
+ * @return the configuration instance (not {@code null})
+ * @throws IllegalArgumentException if a required property does not have a value
+ */
+ I build();
+
+ /**
+ * Get a builder instance for the given configuration interface.
+ *
+ * @param interfaceClass the interface class object (must not be {@code null})
+ * @param the configuration interface type
+ * @return a new builder for the configuration interface (not {@code null})
+ * @throws IllegalArgumentException if the interface class is {@code null},
+ * or if the class object does not represent an interface,
+ * or if the interface is not a valid configuration interface,
+ * or if the interface has one or more required properties that were not given a value,
+ * or if the interface has one or more converters that could not be instantiated
+ * @throws SecurityException if this class does not have permission to introspect the given interface
+ * or one of its superinterfaces
+ */
+ static ConfigInstanceBuilder forInterface(Class interfaceClass)
+ throws IllegalArgumentException, SecurityException {
+ return ConfigInstanceBuilderImpl.forInterface(interfaceClass);
+ }
+}
diff --git a/implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilderImpl.java b/implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilderImpl.java
new file mode 100644
index 000000000..c0ae84adc
--- /dev/null
+++ b/implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilderImpl.java
@@ -0,0 +1,418 @@
+package io.smallrye.config;
+
+import static io.smallrye.config.ConfigMessages.msg;
+
+import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.SerializedLambda;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import org.eclipse.microprofile.config.spi.Converter;
+
+import io.smallrye.common.constraint.Assert;
+import sun.reflect.ReflectionFactory;
+
+/**
+ * The implementation for configuration instance builders.
+ */
+final class ConfigInstanceBuilderImpl implements ConfigInstanceBuilder {
+
+ /**
+ * Reflection factory, used for getting the serialized lambda information out of a getter reference.
+ */
+ private static final ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
+ /**
+ * Stack walker for getting caller class, used for setter caching.
+ */
+ private static final StackWalker sw = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+ /**
+ * Our cached lookup object.
+ */
+ private static final MethodHandles.Lookup myLookup = MethodHandles.lookup();
+ /**
+ * Class value which holds the cached builder class instance.
+ */
+ private static final ClassValue> builderFactories = new ClassValue<>() {
+ protected Supplier> computeValue(final Class> type) {
+ assert type.isInterface();
+ String interfaceName = type.getName();
+ MethodHandles.Lookup lookup;
+ try {
+ lookup = MethodHandles.privateLookupIn(type, myLookup);
+ } catch (IllegalAccessException e) {
+ throw msg.accessDenied(getClass(), type);
+ }
+ String implInternalName = interfaceName.replace('.', '/') + "$$SC_BuilderImpl";
+ Class> impl;
+ try {
+ impl = lookup.findClass(implInternalName);
+ } catch (ClassNotFoundException e) {
+ // generate the impl instead
+ throw new UnsupportedOperationException("Todo");
+ } catch (IllegalAccessException e) {
+ throw msg.accessDenied(getClass(), type);
+ }
+ MethodHandle mh;
+ try {
+ mh = lookup.findConstructor(impl, MethodType.methodType(void.class));
+ } catch (NoSuchMethodException e) {
+ throw msg.noConstructor(impl);
+ } catch (IllegalAccessException e) {
+ throw msg.accessDenied(getClass(), impl);
+ }
+ // capture the constructor as a Supplier
+ return () -> {
+ try {
+ return (ConfigInstanceBuilderImpl>) mh.invokeExact();
+ } catch (RuntimeException | Error e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new UndeclaredThrowableException(e);
+ }
+ };
+ }
+ };
+ /**
+ * Class value which holds the cached config class instance constructors.
+ */
+ private static final ClassValue> configFactories = new ClassValue<>() {
+ protected Function