diff --git a/changelog/13503.bugfix.rst b/changelog/13503.bugfix.rst
new file mode 100644
index 00000000000..1edcf346c34
--- /dev/null
+++ b/changelog/13503.bugfix.rst
@@ -0,0 +1 @@
+Dictionary keys in assertion failure output now preserve insertion order instead of being sorted alphabetically, matching Python's dict behavior since 3.7+.
diff --git a/src/_pytest/_io/pprint.py b/src/_pytest/_io/pprint.py
index 28f06909206..ec41b449ddf 100644
--- a/src/_pytest/_io/pprint.py
+++ b/src/_pytest/_io/pprint.py
@@ -162,7 +162,7 @@ def _pprint_dict(
) -> None:
write = stream.write
write("{")
- items = sorted(object.items(), key=_safe_tuple)
+ items = object.items()
self._format_dict_items(items, stream, indent, allowance, context, level)
write("}")
@@ -608,7 +608,7 @@ def _safe_repr(
components: list[str] = []
append = components.append
level += 1
- for k, v in sorted(object.items(), key=_safe_tuple):
+ for k, v in object.items():
krepr = self._safe_repr(k, context, maxlevels, level)
vrepr = self._safe_repr(v, context, maxlevels, level)
append(f"{krepr}: {vrepr}")
diff --git a/testing/io/test_pprint.py b/testing/io/test_pprint.py
index 1326ef34b2e..be54fdb1e5e 100644
--- a/testing/io/test_pprint.py
+++ b/testing/io/test_pprint.py
@@ -406,3 +406,84 @@ class DataclassWithTwoItems:
)
def test_consistent_pretty_printer(data: Any, expected: str) -> None:
assert PrettyPrinter().pformat(data) == textwrap.dedent(expected).strip()
+
+
+def test_dict_preserves_insertion_order() -> None:
+ """Test that dictionary keys maintain insertion order, not alphabetical.
+
+ Relates to issue #13503 - dicts should preserve insertion order
+ since Python 3.7+, not sort alphabetically.
+ """
+ # Create dict with non-alphabetical insertion order
+ d = {}
+ d["z"] = 1
+ d["a"] = 2
+ d["m"] = 3
+
+ result = PrettyPrinter().pformat(d)
+
+ # Verify the keys appear in insertion order (z, a, m)
+ z_pos = result.index("'z'")
+ a_pos = result.index("'a'")
+ m_pos = result.index("'m'")
+
+ # z should appear before a, and a before m
+ assert z_pos < a_pos < m_pos, (
+ f"Expected insertion order z None:
+ """Test dict insertion order in _safe_repr (used with maxlevels/depth).
+
+ This test ensures the _safe_repr method also preserves insertion order
+ when it formats dicts at maximum depth levels.
+ """
+ # Create nested dict structure with non-alphabetical keys
+ d = {"z": {"inner": 1}, "a": {"inner": 2}, "m": {"inner": 3}}
+
+ # Use depth parameter to trigger _safe_repr path
+ pp = PrettyPrinter(depth=1)
+ result = pp.pformat(d)
+
+ # Verify insertion order is preserved (z before a before m)
+ z_pos = result.index("'z'")
+ a_pos = result.index("'a'")
+ m_pos = result.index("'m'")
+ assert z_pos < a_pos < m_pos, (
+ f"Expected insertion order z None:
+ """Test dict insertion order in _safe_repr inline representation.
+
+ This covers the _safe_repr dict formatting code path used for
+ inline/fallback representations.
+ """
+ pp = PrettyPrinter()
+
+ # Create a dict that will be rendered inline via _safe_repr
+ d = {"z": 1, "a": 2, "m": 3}
+
+ # Call _safe_repr directly to ensure that code path is covered
+ result = pp._safe_repr(d, set(), None, 0)
+
+ # Verify insertion order is preserved in the inline repr
+ z_pos = result.index("'z'")
+ a_pos = result.index("'a'")
+ m_pos = result.index("'m'")
+ assert z_pos < a_pos < m_pos, (
+ f"Expected insertion order z