diff --git a/src/Hl7.Fhir.Base/ElementModel/PocoBuilderNew.cs b/src/Hl7.Fhir.Base/ElementModel/PocoBuilderNew.cs
new file mode 100644
index 000000000..689b82bb9
--- /dev/null
+++ b/src/Hl7.Fhir.Base/ElementModel/PocoBuilderNew.cs
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018, Firely (info@fire.ly) and contributors
+ * See the file CONTRIBUTORS for details.
+ *
+ * This file is licensed under the BSD 3-Clause license
+ * available at https://github.com/FirelyTeam/firely-net-sdk/blob/master/LICENSE
+ */
+
+#nullable enable
+
+using Hl7.Fhir.ElementModel;
+using Hl7.Fhir.Introspection;
+using Hl7.Fhir.Model;
+using Hl7.Fhir.Utility;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Hl7.Fhir.Serialization;
+
+internal class PocoBuilderNew(ModelInspector inspector)
+{
+ ///
+ /// Build a POCO from an .
+ ///
+ public Base BuildFrom(ITypedElement source)
+ {
+ if (source == null) throw Error.ArgumentNull(nameof(source));
+
+ return readFromElement(source);
+ }
+
+ private static readonly string DYNAMIC_RESOURCE_TYPE_NAME = new DynamicResource().TypeName;
+ private static readonly string DYNAMIC_DATATYPE_TYPE_NAME = new DynamicDataType().TypeName;
+ private static readonly string DYNAMIC_PRIMITIVE_TYPE_NAME = new DynamicDataType().TypeName;
+
+ private Base readFromElement(ITypedElement node, ClassMapping? backboneClass=null)
+ {
+ // The classMapping we need to use is either the one provided by the node, or the default Dynamic one.
+ // Design note: This means that the type must be known by name through the inspector, so all types need
+ // to have been loaded in advance.
+ // We are currently not requiring this (although it is already good practice), but since
+ // the old code used `FindOrImport`, and used the element's type in the PropertyMapping, we would create
+ // mappings for types we didn't know about. This gave subtle error, e.g. where the type you are parsing
+ // is in Base, but contains elements from Conformance (like Bundle.entry). In this case, we would create the
+ // mapping for such types, but we would not know the correct FHIR version (since we're dealing with Base, which
+ // is shared), so if the loaded types contained `Since` attributes, we would get the wrong version.
+ // Forcing the user to load the correct FHIR version into our inspector would do away with this incorrect
+ // behaviour.
+ // If the node's InstanceType is a backbone, we're getting the classMapping for that backbone passed in
+ // by our caller, so use that instead.
+ var classMapping = backboneClass ?? getClassMappingForInstanceType(node);
+
+ // Now, create an instance from this mapping.
+ // Note: There may be ClassMappings for .NET and CQL types, but we really cannot handle those and they
+ // will not normally appear on InstanceType for us.
+ var newInstance = classMapping.Factory() switch
+ {
+ Base b => b.AsDictionary(),
+ _ => throw Error.InvalidOperation($"Can only handle Base-derived POCOs, which '{classMapping.NativeType.Name}' is not.")
+ };
+
+ // Value is a kind of pseudo-property, so we need to handle it separately.
+ // Note: this will set the underlying ObjectValue property on the PrimitiveType instance at this moment,
+ // which might not be exactly the expected type. Certainly, it is not expecting the CQL types used
+ // on node.Value, so we still have some mapping work to do here.
+ // If the ITypedElement.InstanceType does not agree with the type of the element in the poco, all use of
+ // the indexers/list.Add below will throw. This is highly unlikely (assuming the source of metadata in the
+ // TypedElement is the same as the reflected data on the POCO - but this is not guaranteed). If we want,
+ // we can turn it into an error annotation.
+ // This will also go wrong where the [DeclaredType] (which is what InstanceType is) is different from
+ // the property type in the POCO - but I hope all declared types are assignable to the property types.
+ // Need to check this. There is no guarantee in any case.
+ if (node.Value is { } value)
+ newInstance["value"] = value;
+
+ // Now, read the children
+ foreach (var child in node.Children())
+ {
+ // Although InstanceType suggests this is a run-time type, we have misdesigned this property
+ // to also return abstract types, in this case, Backbones. Would love to fix this in SDK6.0,
+ // but it would be one of the bigger breaking behavioural changes.
+ var convertedValue = child.InstanceType switch
+ {
+ "BackboneElement" or "Element" =>
+ readFromElement(child, classMapping.FindMappedElementByName(child.Name)?.PropertyTypeMapping),
+ _ => readFromElement(child)
+ };
+
+ // Note the `Definition?` here. So if this ITypedElement is untyped (we have lost
+ // track of the types since we encountered an unknown type), we will never detect
+ // lists. If such an element would repeat, we would overwrite the previous occurrence,
+ // which is nasty. We should try to detect that an element repeats after all, and swap the
+ // existing instance out for a list, to make sure we don't lose data.
+ if (node.Definition?.IsCollection == true)
+ {
+ var list = newInstance.TryGetValue(child.Name, out var existing)
+ ? (IList)existing
+ : classMapping.ListFactory();
+
+ list.Add(convertedValue);
+ }
+ else
+ {
+ newInstance[child.Name] = convertedValue;
+ }
+ }
+
+ return (Base)newInstance;
+ }
+
+ private ClassMapping getClassMappingForInstanceType(ITypedElement node)
+ {
+ if(node.InstanceType is {} instanceType && inspector.FindClassMapping(instanceType) is { } mapping)
+ return mapping;
+
+ // Ok, so the node does not have a type, or the type is not known. So, let's use one
+ // of the applicable dynamic types. If the node has a resource name (but it was unknown),
+ // we'll create a DynamicResource. If the node has a Value, it's a DynamicPrimitive,
+ // otherwise it's a DynamicDataType.
+ // TODO: if InstanceType has a value, but that type is unknown, we should still set the
+ // TypeName of the created Dynamic below to that string.
+ // Design question: there might be a "strict" option, where we will not create Dynamic types
+ // for unknown types, but throw an error instead.
+ if(node.Value is not null)
+ return getDefaultMapping(DYNAMIC_PRIMITIVE_TYPE_NAME);
+
+ if (node.Annotation() is not null)
+ return getDefaultMapping(DYNAMIC_RESOURCE_TYPE_NAME);
+
+ return getDefaultMapping(DYNAMIC_DATATYPE_TYPE_NAME);
+
+ ClassMapping getDefaultMapping(string dynTypeName) =>
+ inspector.FindClassMapping(dynTypeName) ??
+ throw Error.InvalidOperation($"Cannot find ClassMapping for dynamic type '{dynTypeName}'.");
+ }
+}
\ No newline at end of file