diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h
index be5f0914703f..bd1d06d5c488 100644
--- a/include/libcamera/internal/yaml_parser.h
+++ b/include/libcamera/internal/yaml_parser.h
@@ -72,11 +72,20 @@ private:
 		Value,
 	};
 
+	struct Value {
+		Value(std::string &&k, std::unique_ptr<YamlObject> &&v)
+			: key(std::move(k)), value(std::move(v))
+		{
+		}
+		std::string key;
+		std::unique_ptr<YamlObject> value;
+	};
+
 	Type type_;
 
 	std::string value_;
-	std::vector<std::unique_ptr<YamlObject>> list_;
-	std::map<const std::string, std::unique_ptr<YamlObject>> dictionary_;
+	std::vector<Value> list_;
+	std::map<std::string, YamlObject *> dictionary_;
 };
 
 class YamlParser final
diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp
index 85f6694f5fde..83813e2a8552 100644
--- a/src/libcamera/yaml_parser.cpp
+++ b/src/libcamera/yaml_parser.cpp
@@ -90,7 +90,6 @@ std::size_t YamlObject::size() const
 {
 	switch (type_) {
 	case Type::Dictionary:
-		return dictionary_.size();
 	case Type::List:
 		return list_.size();
 	default:
@@ -245,11 +244,11 @@ Size YamlObject::get(const Size &defaultValue, bool *ok) const
 	 * that ok == nullptr.
 	 */
 	bool valid;
-	uint32_t width = list_[0]->get<uint32_t>(0, &valid);
+	uint32_t width = list_[0].value->get<uint32_t>(0, &valid);
 	if (!valid)
 		return defaultValue;
 
-	uint32_t height = list_[1]->get<uint32_t>(0, &valid);
+	uint32_t height = list_[1].value->get<uint32_t>(0, &valid);
 	if (!valid)
 		return defaultValue;
 
@@ -274,7 +273,7 @@ const YamlObject &YamlObject::operator[](std::size_t index) const
 	if (type_ != Type::List || index >= size())
 		return empty;
 
-	return *list_[index];
+	return *list_[index].value;
 }
 
 /**
@@ -290,7 +289,7 @@ const YamlObject &YamlObject::operator[](std::size_t index) const
  */
 bool YamlObject::contains(const std::string &key) const
 {
-	if (dictionary_.find(key) == dictionary_.end())
+	if (dictionary_.find(std::ref(key)) == dictionary_.end())
 		return false;
 
 	return true;
@@ -312,7 +311,7 @@ bool YamlObject::contains(const std::string &key) const
 std::vector<std::string> YamlObject::memberNames() const
 {
 	std::vector<std::string> memberNames;
-	for (auto &[key, _] : dictionary_)
+	for (auto &[key, _] : list_)
 		memberNames.push_back(key);
 
 	return memberNames;
@@ -584,16 +583,16 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even
 		yamlObject.type_ = YamlObject::Type::List;
 		auto &list = yamlObject.list_;
 		auto handler = [this, &list](EventPtr evt) {
-			list.emplace_back(new YamlObject());
-			return parseNextYamlObject(*list.back(), std::move(evt));
+			list.emplace_back(std::string{}, std::make_unique<YamlObject>());
+			return parseNextYamlObject(*list.back().value, std::move(evt));
 		};
 		return parseDictionaryOrList(YamlObject::Type::List, handler);
 	}
 
 	case YAML_MAPPING_START_EVENT: {
 		yamlObject.type_ = YamlObject::Type::Dictionary;
-		auto &dictionary = yamlObject.dictionary_;
-		auto handler = [this, &dictionary](EventPtr evtKey) {
+		auto &list = yamlObject.list_;
+		auto handler = [this, &list](EventPtr evtKey) {
 			/* Parse key */
 			if (evtKey->type != YAML_SCALAR_EVENT) {
 				LOG(YamlParser, Error) << "Expect key at line: "
@@ -611,10 +610,19 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even
 			if (!evtValue)
 				return -EINVAL;
 
-			auto elem = dictionary.emplace(key, std::make_unique<YamlObject>());
-			return parseNextYamlObject(*elem.first->second.get(), std::move(evtValue));
+			auto &elem = list.emplace_back(std::move(key),
+						       std::make_unique<YamlObject>());
+			return parseNextYamlObject(*elem.value, std::move(evtValue));
 		};
-		return parseDictionaryOrList(YamlObject::Type::Dictionary, handler);
+		int ret = parseDictionaryOrList(YamlObject::Type::Dictionary, handler);
+		if (ret)
+			return ret;
+
+		auto &dictionary = yamlObject.dictionary_;
+		for (const auto &elem : list)
+			dictionary.emplace(elem.key, elem.value.get());
+
+		return 0;
 	}
 
 	default:
@@ -670,6 +678,9 @@ int YamlParserContext::parseNextYamlObject(YamlObject &yamlObject, EventPtr even
  * The YamlParser::parse() function takes an open FILE, parses its contents, and
  * returns a pointer to a YamlObject corresponding to the root node of the YAML
  * document.
+ *
+ * The parser preserves the order of items in the YAML file, for both lists and
+ * dictionaries.
  */
 
 /**
