Add new public Map reflection API.

The new API provides a map-like interface that can be accessed via `Reflection::GetMap` and `Reflection::MutableMap`. This API accesses the underlying Map type directly and avoid the fake repeated field we see today via the legacy reflection API.

In a future breaking change, the repeated field based access for maps will be removed and the only valid reflection will be this new API.

PiperOrigin-RevId: 987589348
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index 207b952..ea9dddd 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -17,6 +17,7 @@
 #include <optional>
 #include <string>
 
+#include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/map.h"
 #include "google/protobuf/map_field.h"
@@ -59,7 +60,7 @@
   // clang-format off
   PyObject_HEAD
 
-  std::unique_ptr<::google::protobuf::ConstMapIterator> iter;
+  ::google::protobuf::GenericConstMapRef::const_iterator iter;
   // clang-format on
 
   // A pointer back to the container, so we can notice changes to the version.
@@ -196,64 +197,64 @@
 // CPPTYPE_MESSAGE case.
 static bool PythonToMapValueRef(MapContainer* self, PyObject* obj,
                                 bool allow_unknown_enum_values,
-                                MapValueRef* value_ref) {
+                                MapValueRef value_ref) {
   const FieldDescriptor* field_descriptor =
       self->parent_field_descriptor->message_type()->map_value();
   switch (field_descriptor->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32: {
       PROTOBUF_CHECK_GET_INT32(obj, value, false);
-      value_ref->SetInt32Value(value);
+      value_ref.SetInt32Value(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_INT64: {
       PROTOBUF_CHECK_GET_INT64(obj, value, false);
-      value_ref->SetInt64Value(value);
+      value_ref.SetInt64Value(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_UINT32: {
       PROTOBUF_CHECK_GET_UINT32(obj, value, false);
-      value_ref->SetUInt32Value(value);
+      value_ref.SetUInt32Value(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_UINT64: {
       PROTOBUF_CHECK_GET_UINT64(obj, value, false);
-      value_ref->SetUInt64Value(value);
+      value_ref.SetUInt64Value(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_FLOAT: {
       PROTOBUF_CHECK_GET_FLOAT(obj, value, false);
-      value_ref->SetFloatValue(value);
+      value_ref.SetFloatValue(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_DOUBLE: {
       PROTOBUF_CHECK_GET_DOUBLE(obj, value, false);
-      value_ref->SetDoubleValue(value);
+      value_ref.SetDoubleValue(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_BOOL: {
       PROTOBUF_CHECK_GET_BOOL(obj, value, false);
-      value_ref->SetBoolValue(value);
+      value_ref.SetBoolValue(value);
       return true;
     }
     case FieldDescriptor::CPPTYPE_STRING: {
       std::optional<absl::string_view> value =
           CheckString(obj, field_descriptor);
       if (value.has_value()) {
-        value_ref->SetStringValue(*value);
+        value_ref.SetStringValue(*value);
       }
       return value.has_value();
     }
     case FieldDescriptor::CPPTYPE_ENUM: {
       PROTOBUF_CHECK_GET_INT32(obj, value, false);
       if (allow_unknown_enum_values) {
-        value_ref->SetEnumValue(value);
+        value_ref.SetEnumValue(value);
         return true;
       } else {
         const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
         const EnumValueDescriptor* enum_value =
             enum_descriptor->FindValueByNumber(value);
         if (enum_value != nullptr) {
-          value_ref->SetEnumValue(value);
+          value_ref.SetEnumValue(value);
           return true;
         } else {
           PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value);
@@ -270,6 +271,26 @@
   }
 }
 
+static std::optional<MapValueRef> TryEmplace(Message* message,
+                                             MapContainer* self,
+                                             MapKey map_key) {
+  auto map = message->GetReflection()->MutableMap(
+      message, self->parent_field_descriptor);
+  if (!map.ok()) {
+    PyErr_SetString(PyExc_SystemError, map.status().ToString().c_str());
+    return std::nullopt;
+  }
+  auto res = map->try_emplace(map_key);
+  if (!res.ok()) {
+    PyErr_SetString(PyExc_SystemError, res.status().ToString().c_str());
+    return std::nullopt;
+  }
+  if (res->inserted) {
+    self->version++;
+  }
+  return res->iter->value();
+}
+
 // Map methods common to ScalarMap and MessageMap //////////////////////////////
 
 static MapContainer* GetMap(PyObject* obj) {
@@ -279,8 +300,9 @@
 Py_ssize_t MapReflectionFriend::Length(PyObject* _self) {
   MapContainer* self = GetMap(_self);
   const google::protobuf::Message* message = self->parent->message;
-  return message->GetReflection()->MapSize(*message,
-                                           self->parent_field_descriptor);
+  auto map =
+      message->GetReflection()->GetMap(*message, self->parent_field_descriptor);
+  return map.ok() ? map->size() : 0;
 }
 
 PyObject* Clear(PyObject* _self) {
@@ -337,8 +359,8 @@
     return -1;
   }
 
-  if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
-                                 map_key)) {
+  auto map = reflection->GetMap(*message, self->parent_field_descriptor);
+  if (map.ok() && map->contains(map_key)) {
     return 1;
   } else {
     return 0;
@@ -382,10 +404,11 @@
   // 1. Read-only lookup without mutation if key exists.
   const Message* message = self->GetReadOnlyMessage();
   const Reflection* reflection = message->GetReflection();
-  MapValueConstRef value;
-  if (reflection->LookupMapValue(*message, self->parent_field_descriptor,
-                                 map_key, &value)) {
-    return MapValueRefToPython(self, value);
+  auto map = reflection->GetMap(*message, self->parent_field_descriptor);
+  if (map.ok()) {
+    if (auto it = map->find(map_key); it != map->end()) {
+      return MapValueRefToPython(self, it->value());
+    }
   }
 
   // 2. Frozen path: read-only lookup failed and message is frozen.
@@ -396,14 +419,9 @@
   // 3. Mutable path: insert default value for missing key.
   if (Message* mutable_message = self->GetMutableMessage();
       mutable_message != nullptr) {
-    MapValueRef mutable_value;
-    const Reflection* mutable_reflection = mutable_message->GetReflection();
-    if (mutable_reflection->InsertOrLookupMapValue(
-            mutable_message, self->parent_field_descriptor, map_key,
-            &mutable_value)) {
-      self->version++;
-    }
-    return MapValueRefToPython(self, mutable_value);
+    auto value = TryEmplace(mutable_message, self, map_key);
+    if (!value.has_value()) return nullptr;
+    return MapValueRefToPython(self, *value);
   }
 
   return nullptr;
@@ -417,31 +435,27 @@
   if (message == nullptr) return -1;
   const Reflection* reflection = message->GetReflection();
   MapKey map_key;
-  MapValueRef value;
 
   if (!PythonToMapKey(self, key, &map_key)) {
     return -1;
   }
 
   if (v) {
+    auto value = TryEmplace(message, self, map_key);
+    if (!value.has_value()) return -1;
     // Set item to v.
-    if (reflection->InsertOrLookupMapValue(
-            message, self->parent_field_descriptor, map_key, &value)) {
-      self->version++;
-    }
-
     if (!PythonToMapValueRef(self, v,
                              !self->parent_field_descriptor->message_type()
                                   ->map_value()
                                   ->legacy_enum_field_treated_as_closed(),
-                             &value)) {
+                             *value)) {
       return -1;
     }
     return 0;
   } else {
     // Delete key from map.
-    if (reflection->DeleteMapValue(message, self->parent_field_descriptor,
-                                   map_key)) {
+    auto map = reflection->MutableMap(message, self->parent_field_descriptor);
+    if (map.ok() && map->erase(map_key)) {
       self->version++;
       return 0;
     } else {
@@ -519,20 +533,20 @@
   MapContainer* self = GetMap(_self);
   const Message* message = self->GetReadOnlyMessage();
   const Reflection* reflection = message->GetReflection();
-  for (google::protobuf::ConstMapIterator it =
-           reflection->ConstMapBegin(message, self->parent_field_descriptor);
-       it != reflection->ConstMapEnd(message, self->parent_field_descriptor);
-       ++it) {
-    key.reset(MapKeyToPython(self, it.GetKey()));
-    if (key == nullptr) {
-      return nullptr;
-    }
-    value.reset(MapValueRefToPython(self, it.GetValueRef()));
-    if (value == nullptr) {
-      return nullptr;
-    }
-    if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
-      return nullptr;
+  auto map = reflection->GetMap(*message, self->parent_field_descriptor);
+  if (map.ok()) {
+    for (auto entry : *map) {
+      key.reset(MapKeyToPython(self, entry.key()));
+      if (key == nullptr) {
+        return nullptr;
+      }
+      value.reset(MapValueRefToPython(self, entry.value()));
+      if (value == nullptr) {
+        return nullptr;
+      }
+      if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
+        return nullptr;
+      }
     }
   }
   return PyObject_Repr(dict.get());
@@ -651,13 +665,14 @@
   }
 
   // Delete key from map.
-  if (reflection->ContainsMapKey(*message, self->parent_field_descriptor,
-                                 map_key)) {
+  auto map = reflection->MutableMap(message, self->parent_field_descriptor);
+  if (!map.ok()) {
+    PyErr_Format(PyExc_KeyError, "Key not present in map");
+    return -1;
+  }
+  if (auto it = map->find(map_key); it != map->end()) {
     // Delete key from CMessage dict.
-    MapValueRef value;
-    reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor,
-                                       map_key, &value);
-    Message* sub_message = value.MutableMessageValue();
+    Message* sub_message = it->value().MutableMessageValue();
     // If there is a living weak reference to an item, we "Release" it,
     // otherwise we just discard the C++ value.
     if (CMessage* released =
@@ -670,7 +685,7 @@
     }
 
     // Delete key from map.
-    reflection->DeleteMapValue(message, self->parent_field_descriptor, map_key);
+    map->erase(map_key);
     return 0;
   } else {
     PyErr_Format(PyExc_KeyError, "Key not present in map");
@@ -696,13 +711,14 @@
   // 1. Read-only lookup without mutation if key exists.
   const Message* message = self->GetReadOnlyMessage();
   const Reflection* reflection = message->GetReflection();
-  MapValueConstRef value;
-  if (reflection->LookupMapValue(*message, self->parent_field_descriptor,
-                                 map_key, &value)) {
-    MessageMutabilityState state = self->parent->state == MESSAGE_FROZEN
-                                       ? MESSAGE_FROZEN
-                                       : MESSAGE_UNPROMOTED;
-    return GetCMessage(self, &value.GetMessageValue(), state);
+  auto map = reflection->GetMap(*message, self->parent_field_descriptor);
+  if (map.ok()) {
+    if (auto it = map->find(map_key); it != map->end()) {
+      MessageMutabilityState state = self->parent->state == MESSAGE_FROZEN
+                                         ? MESSAGE_FROZEN
+                                         : MESSAGE_UNPROMOTED;
+      return GetCMessage(self, &it->value().GetMessageValue(), state);
+    }
   }
 
   // 2. Frozen path: read-only lookup failed and message is frozen.
@@ -713,15 +729,9 @@
   // 3. Mutable path: insert default submessage for missing key.
   if (Message* mutable_message = self->GetMutableMessage();
       mutable_message != nullptr) {
-    const Reflection* mutable_reflection = mutable_message->GetReflection();
-    MapValueRef mutable_value;
-    if (mutable_reflection->InsertOrLookupMapValue(
-            mutable_message, self->parent_field_descriptor, map_key,
-            &mutable_value)) {
-      self->version++;
-    }
-    return GetCMessage(self, mutable_value.MutableMessageValue(),
-                       MESSAGE_MUTABLE);
+    auto value = TryEmplace(mutable_message, self, map_key);
+    if (!value.has_value()) return nullptr;
+    return GetCMessage(self, value->MutableMessageValue(), MESSAGE_MUTABLE);
   }
 
   return nullptr;
@@ -744,20 +754,20 @@
   MessageMutabilityState state = self->parent->state == MESSAGE_FROZEN
                                      ? MESSAGE_FROZEN
                                      : MESSAGE_UNPROMOTED;
-  for (google::protobuf::ConstMapIterator it =
-           reflection->ConstMapBegin(message, self->parent_field_descriptor);
-       it != reflection->ConstMapEnd(message, self->parent_field_descriptor);
-       ++it) {
-    key.reset(MapKeyToPython(self, it.GetKey()));
-    if (key == nullptr) {
-      return nullptr;
-    }
-    value.reset(GetCMessage(self, &it.GetValueRef().GetMessageValue(), state));
-    if (value == nullptr) {
-      return nullptr;
-    }
-    if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
-      return nullptr;
+  auto map = reflection->GetMap(*message, self->parent_field_descriptor);
+  if (map.ok()) {
+    for (auto entry : *map) {
+      key.reset(MapKeyToPython(self, entry.key()));
+      if (key == nullptr) {
+        return nullptr;
+      }
+      value.reset(GetCMessage(self, &entry.value().GetMessageValue(), state));
+      if (value == nullptr) {
+        return nullptr;
+      }
+      if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) {
+        return nullptr;
+      }
     }
   }
   return PyObject_Repr(dict.get());
@@ -889,13 +899,12 @@
   Py_INCREF(self->parent);
   iter->parent = self->parent;
 
-  if (MapReflectionFriend::Length(_self) > 0) {
-    const Message* message = self->GetReadOnlyMessage();
-    const Reflection* reflection = message->GetReflection();
+  const Message* message = self->GetReadOnlyMessage();
+  const Reflection* reflection = message->GetReflection();
 
-    iter->iter = std::make_unique<::google::protobuf::ConstMapIterator>(
-        reflection->ConstMapBegin(message, self->parent_field_descriptor));
-  }
+  iter->iter = reflection->GetMap(*message, self->parent_field_descriptor)
+                   .value()
+                   .begin();
 
   return obj.release();
 }
@@ -910,28 +919,29 @@
     return PyErr_Format(PyExc_RuntimeError, "Map cleared during iteration.");
   }
 
-  if (self->iter == nullptr) {
+  if (self->iter == ::google::protobuf::GenericConstMapRef::const_iterator{}) {
     return nullptr;
   }
 
   const Message* message = self->container->GetReadOnlyMessage();
   const Reflection* reflection = message->GetReflection();
 
-  if (*self->iter == reflection->ConstMapEnd(
-                         message, self->container->parent_field_descriptor)) {
+  if (self->iter ==
+      reflection->GetMap(*message, self->container->parent_field_descriptor)
+          .value()
+          .end()) {
     return nullptr;
   }
 
-  PyObject* ret = MapKeyToPython(self->container, self->iter->GetKey());
+  PyObject* ret = MapKeyToPython(self->container, self->iter->key());
 
-  ++(*self->iter);
+  ++self->iter;
 
   return ret;
 }
 
 static void DeallocMapIterator(PyObject* _self) {
   MapIterator* self = GetIter(_self);
-  self->iter.reset();
   Py_CLEAR(self->container);
   Py_CLEAR(self->parent);
   Py_TYPE(_self)->tp_free(_self);
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 06c5d6a..f14d61b 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -91,12 +91,6 @@
       const std::vector<const FieldDescriptor*>& fields) {
     lhs->GetReflection()->UnsafeShallowSwapFields(lhs, rhs, fields);
   }
-  static bool ContainsMapKey(const Reflection* reflection,
-                             const Message& message,
-                             const FieldDescriptor* field,
-                             const MapKey& map_key) {
-    return reflection->ContainsMapKey(message, field, map_key);
-  }
 
   static void SetString(absl::string_view value, Message* message,
                         const FieldDescriptor* descriptor,
@@ -2716,8 +2710,8 @@
       }
       map_key.SetStringValue(*key_string);
 
-      return PyBool_FromLong(MessageReflectionFriend::ContainsMapKey(
-          reflection, *message, map_field, map_key));
+      auto map = reflection->GetMap(*message, map_field);
+      return PyBool_FromLong(map.ok() && map->contains(map_key));
     }
     case Descriptor::WELLKNOWNTYPE_LISTVALUE: {
       // For WKT ListValue, check if the key is in the items.
diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel
index 3d74021..4bfbfe4 100644
--- a/src/google/protobuf/BUILD.bazel
+++ b/src/google/protobuf/BUILD.bazel
@@ -1897,7 +1897,11 @@
         "@abseil-cpp//absl/base:log_severity",
         "@abseil-cpp//absl/container:flat_hash_map",
         "@abseil-cpp//absl/flags:flag",
+        "@abseil-cpp//absl/functional:overload",
         "@abseil-cpp//absl/log:absl_check",
+        "@abseil-cpp//absl/log:absl_log",
+        "@abseil-cpp//absl/status:status_matchers",
+        "@abseil-cpp//absl/status:statusor",
         "@abseil-cpp//absl/strings",
         "@abseil-cpp//absl/time",
         "@abseil-cpp//absl/types:optional",
@@ -2531,6 +2535,8 @@
         "@abseil-cpp//absl/log:globals",
         "@abseil-cpp//absl/random",
         "@abseil-cpp//absl/random:distributions",
+        "@abseil-cpp//absl/status:status_matchers",
+        "@abseil-cpp//absl/status:statusor",
         "@abseil-cpp//absl/strings",
         "@abseil-cpp//absl/strings:str_format",
         "@abseil-cpp//absl/time",
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 9a6ff3a..bb4863c 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -31,6 +31,8 @@
 #include "absl/container/flat_hash_set.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/numbers.h"
 #include "absl/strings/str_cat.h"
@@ -311,21 +313,40 @@
   }
 }
 
+absl::Status ReflectionUsageError(const Descriptor* descriptor,
+                                  const FieldDescriptor* field,
+                                  absl::string_view method,
+                                  absl::string_view description) {
+  return absl::InvalidArgumentError(absl::StrCat(
+      "Protocol Buffer reflection usage error:\n"
+      "  Method      : google::protobuf::Reflection::",
+      method, "\n", "  Message type: ",
+      descriptor != nullptr ? descriptor->full_name() : "null", "\n",
+      "  Field       : ", field != nullptr ? field->full_name() : "null", "\n",
+      "  Problem     : ", description));
+}
+
 void ReportReflectionUsageError(const Descriptor* descriptor,
                                 const FieldDescriptor* field,
                                 const char* method, const char* description) {
-  ABSL_LOG(FATAL) << "Protocol Buffer reflection usage error:\n"
-                     "  Method      : google::protobuf::Reflection::"
-                  << method
-                  << "\n"
-                     "  Message type: "
-                  << descriptor->full_name()
-                  << "\n"
-                     "  Field       : "
-                  << field->full_name()
-                  << "\n"
-                     "  Problem     : "
-                  << description;
+  ABSL_LOG(FATAL) << ReflectionUsageError(descriptor, field, method,
+                                          description);
+}
+
+absl::Status ReflectionUsageMessageError(const Descriptor* expected,
+                                         const Descriptor* actual,
+                                         const FieldDescriptor* field,
+                                         absl::string_view method) {
+  return absl::InvalidArgumentError(absl::StrFormat(
+      "Protocol Buffer reflection usage error:\n"
+      "  Method       : google::protobuf::Reflection::%s\n"
+      "  Expected type: %s\n"
+      "  Actual type  : %s\n"
+      "  Field        : %s\n"
+      "  Problem      : Message is not the right object for reflection",
+      method, expected != nullptr ? expected->full_name() : "null",
+      actual != nullptr ? actual->full_name() : "null",
+      field != nullptr ? field->full_name() : "n/a"));
 }
 
 #ifndef NDEBUG
@@ -333,15 +354,8 @@
                                        const Descriptor* actual,
                                        const FieldDescriptor* field,
                                        const char* method) {
-  ABSL_LOG(FATAL) << absl::StrFormat(
-      "Protocol Buffer reflection usage error:\n"
-      "  Method       : google::protobuf::Reflection::%s\n"
-      "  Expected type: %s\n"
-      "  Actual type  : %s\n"
-      "  Field        : %s\n"
-      "  Problem      : Message is not the right object for reflection",
-      method, expected->full_name(), actual->full_name(),
-      (field != nullptr ? field->full_name() : "n/a"));
+  ABSL_LOG(FATAL) << ReflectionUsageMessageError(expected, actual, field,
+                                                 method);
 }
 #endif
 
@@ -1524,7 +1538,7 @@
           } else {
             // No need to materialize the repeated field if it is out of sync:
             // its size will be the same as the map's size.
-            return map.size();
+            return static_cast<int>(map.GetMap().size());
           }
         } else {
           return GetRaw<RepeatedPtrFieldBase>(message, field).size();
@@ -2568,6 +2582,8 @@
 
 const internal::ClassData* Reflection::GetMessageClassData(
     const FieldDescriptor* field) const {
+  ABSL_DCHECK_EQ(descriptor_, field->containing_type())
+      << field->full_name() << " " << descriptor_->full_name();
   // If we are using the generated factory, we cache the prototype in the field
   // descriptor for faster access.
   // The default instances of generated messages are not cross-linked, which
@@ -2948,7 +2964,7 @@
           } else {
             // No need to materialize the repeated field if it is out of sync:
             // its size will be the same as the map's size.
-            return map.size() == 0;
+            return map.GetMap().empty();
           }
         } else {
           return GetRaw<RepeatedPtrFieldBase>(message, field).empty();
@@ -3033,77 +3049,150 @@
 bool Reflection::ContainsMapKey(const Message& message,
                                 const FieldDescriptor* field,
                                 const MapKey& key) const {
-  USAGE_CHECK(IsMapFieldInApi(field), LookupMapValue,
-              "Field is not a map field.");
-  return GetRaw<MapFieldBase>(message, field).ContainsMapKey(key);
+  auto map = GetMap(message, field);
+  return map.ok() && map->contains(key);
 }
 
 bool Reflection::InsertOrLookupMapValue(Message* message,
                                         const FieldDescriptor* field,
                                         const MapKey& key,
                                         MapValueRef* val) const {
-  USAGE_CHECK(IsMapFieldInApi(field), InsertOrLookupMapValue,
-              "Field is not a map field.");
-  val->SetType(field->message_type()->map_value()->cpp_type());
-  SetHasBit(message, field);
-  return MutableRaw<MapFieldBase>(message, field)
-      ->InsertOrLookupMapValue(key, val);
+  auto map = MutableMap(message, field);
+  if (!map.ok()) return false;
+  auto res = map->try_emplace(key);
+  if (!res.ok()) return false;
+  if (val != nullptr) *val = res->iter->value();
+  return res->inserted;
 }
 
 bool Reflection::LookupMapValue(const Message& message,
                                 const FieldDescriptor* field, const MapKey& key,
                                 MapValueConstRef* val) const {
-  USAGE_CHECK(IsMapFieldInApi(field), LookupMapValue,
-              "Field is not a map field.");
-  val->SetType(field->message_type()->map_value()->cpp_type());
-  return GetRaw<MapFieldBase>(message, field).LookupMapValue(key, val);
+  auto map = GetMap(message, field);
+  if (!map.ok()) return false;
+  auto it = map->find(key);
+  if (it != map->end()) {
+    if (val != nullptr) *val = it->value();
+    return true;
+  }
+  return false;
 }
 
 bool Reflection::DeleteMapValue(Message* message, const FieldDescriptor* field,
                                 const MapKey& key) const {
-  USAGE_CHECK(IsMapFieldInApi(field), DeleteMapValue,
-              "Field is not a map field.");
-  return MutableRaw<MapFieldBase>(message, field)
-      ->DeleteMapValue(message->GetArena(), key);
+  auto map = MutableMap(message, field);
+  if (!map.ok()) return false;
+  return map->erase(key);
 }
 
-MapIterator Reflection::MapBegin(Message* message,
-                                 const FieldDescriptor* field) const {
-  USAGE_CHECK(IsMapFieldInApi(field), MapBegin, "Field is not a map field.");
-  MapIterator iter(message, field);
-  GetRaw<MapFieldBase>(*message, field).MapBegin(&iter);
-  return iter;
-}
-
-MapIterator Reflection::MapEnd(Message* message,
-                               const FieldDescriptor* field) const {
-  USAGE_CHECK(IsMapFieldInApi(field), MapEnd, "Field is not a map field.");
-  MapIterator iter(message, field);
-  GetRaw<MapFieldBase>(*message, field).MapEnd(&iter);
-  return iter;
-}
-
+PROTOBUF_IGNORE_DEPRECATION_START
 ConstMapIterator Reflection::ConstMapBegin(const Message* message,
                                            const FieldDescriptor* field) const {
-  USAGE_CHECK(IsMapFieldInApi(field), ConstMapBegin,
-              "Field is not a map field.");
-  ConstMapIterator iter(message, field);
-  GetRaw<MapFieldBase>(*message, field).ConstMapBegin(&iter);
-  return iter;
+  auto map = GetMap(*message, field);
+  if (!map.ok()) return ConstMapIterator();
+  return map->begin();
 }
 
 ConstMapIterator Reflection::ConstMapEnd(const Message* message,
                                          const FieldDescriptor* field) const {
-  USAGE_CHECK(IsMapFieldInApi(field), ConstMapEnd, "Field is not a map field.");
-  ConstMapIterator iter(message, field);
-  GetRaw<MapFieldBase>(*message, field).ConstMapEnd(&iter);
-  return iter;
+  auto map = GetMap(*message, field);
+  if (!map.ok()) return ConstMapIterator();
+  return map->end();
+}
+PROTOBUF_IGNORE_DEPRECATION_STOP
+
+static absl::Status CheckUsage(const Reflection* reflection,
+                               const Descriptor* descriptor,
+                               const Message* message,
+                               const FieldDescriptor* field,
+                               absl::string_view method) {
+  if (ABSL_PREDICT_FALSE(message == nullptr)) {
+    return ReflectionUsageError(descriptor, field, method,
+                                "Message pointer is null.");
+  }
+  if (ABSL_PREDICT_FALSE(field == nullptr)) {
+    return ReflectionUsageError(descriptor, nullptr, method,
+                                "FieldDescriptor is null.");
+  }
+  if (ABSL_PREDICT_FALSE(reflection != message->GetReflection())) {
+    return ReflectionUsageMessageError(descriptor, message->GetDescriptor(),
+                                       field, method);
+  }
+  if (ABSL_PREDICT_FALSE(field->containing_type() != descriptor)) {
+    return ReflectionUsageError(descriptor, field, method,
+                                "Field does not match message type.");
+  }
+  return absl::OkStatus();
+}
+
+static absl::Status CheckMapUsage(const Reflection* reflection,
+                                  const Descriptor* descriptor,
+                                  const Message* message,
+                                  const FieldDescriptor* field,
+                                  absl::string_view method) {
+  if (auto usage = CheckUsage(reflection, descriptor, message, field, method);
+      !usage.ok()) {
+    return usage;
+  }
+  if (ABSL_PREDICT_FALSE(!field->is_map())) {
+    return ReflectionUsageError(
+        descriptor, field, method,
+        "Field is singular or repeated; the method requires a map field.");
+  }
+  return absl::OkStatus();
+}
+
+const internal::ClassData* Reflection::GetClassDataForMapMessageValueType(
+    const FieldDescriptor* field, const internal::UntypedMapBase& map) const {
+  if (field->message_type()->map_value()->message_type() == nullptr) {
+    return nullptr;
+  }
+  if (!map.empty()) {
+    // If the map has elements, use it to get the prototype.
+    return internal::GetClassData(*DownCastMessage<Message>(
+        map.GetValue<MessageLite>(map.begin().node_)));
+  } else {
+    // Otherwise, fall back to reflection get it which is a bit more work.
+    auto* map_entry_prototype = DownCastMessage<Message>(
+        GetMessageClassData(field)->default_instance());
+    return map_entry_prototype->GetReflection()->GetMessageClassData(
+        map_entry_prototype->GetDescriptor()->map_value());
+  }
+}
+
+absl::StatusOr<GenericMapRef> Reflection::MutableMap(
+    Message* message, const FieldDescriptor* field) const {
+  if (auto status =
+          CheckMapUsage(this, descriptor_, message, field, "MutableMap");
+      ABSL_PREDICT_FALSE(!status.ok())) {
+    return status;
+  }
+  GenericMapRef ref;
+  ref.key_type_ = field->message_type()->map_key()->cpp_type();
+  ref.value_type_ = field->message_type()->map_value()->cpp_type();
+  ref.map_ = MutableMapData(message, field)->MutableMap();
+  ref.value_class_data_ = GetClassDataForMapMessageValueType(field, *ref.map_);
+  return ref;
+}
+
+absl::StatusOr<GenericConstMapRef> Reflection::GetMap(
+    const Message& message, const FieldDescriptor* field) const {
+  if (auto status = CheckMapUsage(this, descriptor_, &message, field, "GetMap");
+      ABSL_PREDICT_FALSE(!status.ok())) {
+    return status;
+  }
+  GenericConstMapRef ref;
+  ref.key_type_ = field->message_type()->map_key()->cpp_type();
+  ref.value_type_ = field->message_type()->map_value()->cpp_type();
+  ref.map_ = &GetMapData(message, field)->GetMap();
+  ref.value_class_data_ = GetClassDataForMapMessageValueType(field, *ref.map_);
+  return ref;
 }
 
 int Reflection::MapSize(const Message& message,
                         const FieldDescriptor* field) const {
-  USAGE_CHECK(IsMapFieldInApi(field), MapSize, "Field is not a map field.");
-  return GetRaw<MapFieldBase>(message, field).size();
+  auto map = GetMap(message, field);
+  return map.ok() ? static_cast<int>(map->size()) : 0;
 }
 
 // -----------------------------------------------------------------------------
@@ -4136,12 +4225,14 @@
 
       const auto& map = reflection->GetRaw<MapFieldBase>(root, field);
       if (map.IsMapValid()) {
-        const auto end = reflection->ConstMapEnd(&root, field);
-        for (auto iter = reflection->ConstMapBegin(&root, field); iter != end;
-             ++iter) {
-          const Message& sub_message = iter.GetValueRef().GetMessageValue();
-          if (&sub_message == &message || IsDescendant(sub_message, message)) {
-            return true;
+        auto map_or = reflection->GetMap(root, field);
+        if (map_or.ok()) {
+          for (auto entry : *map_or) {
+            const Message& sub_message = entry.value().GetMessageValue();
+            if (&sub_message == &message ||
+                IsDescendant(sub_message, message)) {
+              return true;
+            }
           }
         }
 
diff --git a/src/google/protobuf/json/internal/unparser.cc b/src/google/protobuf/json/internal/unparser.cc
index aef2359..0405904 100644
--- a/src/google/protobuf/json/internal/unparser.cc
+++ b/src/google/protobuf/json/internal/unparser.cc
@@ -370,9 +370,9 @@
 
   if (Traits::MapFieldUseMapReflection(field, msg)) {
     RETURN_IF_ERROR(Traits::ForEachMapEntry(
-        field, msg, [&](auto it, const auto& type) -> absl::Status {
+        field, msg, [&](auto entry, const auto& type) -> absl::Status {
           auto is_empty =
-              IsEmptyValue<Traits>(it.GetValueRef(), Traits::ValueField(type));
+              IsEmptyValue<Traits>(entry.value(), Traits::ValueField(type));
           RETURN_IF_ERROR(is_empty.status());
           if (*is_empty) {
             // Empty google.protobuf.Values are silently discarded.
@@ -382,11 +382,11 @@
           writer.WriteComma(first);
           writer.NewLine();
           RETURN_IF_ERROR(
-              WriteMapKey<Traits>(writer, it.GetKey(), Traits::KeyField(type)));
+              WriteMapKey<Traits>(writer, entry.key(), Traits::KeyField(type)));
           writer.Write(":");
           writer.Whitespace(" ");
           RETURN_IF_ERROR(WriteSingular<Traits>(
-              writer, Traits::ValueField(type), it.GetValueRef()));
+              writer, Traits::ValueField(type), entry.value()));
           return absl::OkStatus();
         }));
   } else {
diff --git a/src/google/protobuf/json/internal/unparser_traits.h b/src/google/protobuf/json/internal/unparser_traits.h
index 290821b..408995f 100644
--- a/src/google/protobuf/json/internal/unparser_traits.h
+++ b/src/google/protobuf/json/internal/unparser_traits.h
@@ -297,10 +297,9 @@
   static absl::Status ForEachMapEntry(Field f, const Msg& msg, Func func) {
     ABSL_DCHECK(MapFieldUseMapReflection(f, msg));
     const auto& type = *f->message_type();
-    for (auto it = msg.GetReflection()->ConstMapBegin(&msg, f),
-              end = msg.GetReflection()->ConstMapEnd(&msg, f);
-         it != end; ++it) {
-      RETURN_IF_ERROR(func(it, type));
+    ASSIGN_OR_RETURN(auto map, msg.GetReflection()->GetMap(msg, f));
+    for (auto entry : map) {
+      RETURN_IF_ERROR(func(entry, type));
     }
     return absl::OkStatus();
   }
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index f8090bd..5b7bead 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -7,9 +7,9 @@
 
 // This file defines the map container and its helpers to support protobuf maps.
 //
-// The Map and MapIterator types are provided by this header file.
+// The Map type is provided by this header file.
 // Please avoid using other types defined here, unless they are public
-// types within Map or MapIterator, such as Map::value_type.
+// types within Map, such as Map::value_type.
 
 #ifndef GOOGLE_PROTOBUF_MAP_H__
 #define GOOGLE_PROTOBUF_MAP_H__
@@ -58,7 +58,8 @@
 template <typename Key, typename T>
 class Map;
 
-class MapIterator;
+class ABSL_ATTRIBUTE_VIEW GenericMapRef;
+class ABSL_ATTRIBUTE_VIEW GenericConstMapRef;
 
 template <typename Enum>
 struct is_proto_enum;
@@ -413,6 +414,7 @@
   friend struct MapBenchmarkPeer;
   friend class UntypedMapIterator;
   friend class RustMapHelper;
+  friend GenericMapRef;
 
   // Calls `f(type_t)` where `type_t` is an unspecified type that has a `::type`
   // typedef in it representing the dynamic type of key/value of the node.
@@ -612,7 +614,7 @@
 // code, since that would bring in Message too.
 class MapFieldBaseForParse {
  public:
-  const UntypedMapBase& GetMap() const {
+  const UntypedMapBase& GetMap() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
     const void* p = globals_or_payload_.load(std::memory_order_acquire);
     // If this instance has a payload, then it might need sync'n.
     if (ABSL_PREDICT_FALSE(IsPayload(p))) {
@@ -621,7 +623,7 @@
     return GetMapRaw();
   }
 
-  UntypedMapBase* MutableMap() {
+  UntypedMapBase* MutableMap() ABSL_ATTRIBUTE_LIFETIME_BOUND {
     const void* p = globals_or_payload_.load(std::memory_order_acquire);
     // If this instance has a payload, then it might need sync'n.
     if (ABSL_PREDICT_FALSE(IsPayload(p))) {
@@ -734,6 +736,8 @@
   friend struct MapTestPeer;
   friend struct MapBenchmarkPeer;
   friend class RustMapHelper;
+  friend GenericMapRef;
+  friend GenericConstMapRef;
 
   Key* GetKey(NodeBase* node) const {
     return UntypedMapBase::GetKey<Key>(node);
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index b599b8f..e06b05d 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -12,9 +12,12 @@
 #include <cstdint>
 #include <string>
 #include <type_traits>
+#include <utility>
 
 #include "absl/functional/overload.h"
 #include "absl/log/absl_check.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
 #include "absl/synchronization/mutex.h"
 #include "google/protobuf/arena.h"
 #include "google/protobuf/descriptor.h"
@@ -80,119 +83,10 @@
   }
 }
 
-bool MapFieldBase::InsertOrLookupMapValueNoSync(const MapKey& map_key,
-                                                MapValueRef* val) {
-  if (LookupMapValueNoSync(map_key, static_cast<MapValueConstRef*>(val))) {
-    return false;
-  }
-
-  auto& map = GetMapRaw();
-  Arena* arena = map.arena();
-
-  NodeBase* node = map.AllocNode(arena);
-  map.VisitValue(node, [&](auto* v) { InitializeKeyValue(v); });
-  val->SetValue(map.GetVoidValue(node));
-
-  return VisitMapKey(map_key, map, [&](auto& map, const auto& key) {
-    InitializeKeyValue(map.GetKey(node), key);
-    map.InsertOrReplaceNode(
-        arena,
-        static_cast<typename std::decay_t<decltype(map)>::KeyNode*>(node));
-    return true;
-  });
-}
-
-bool MapFieldBase::DeleteMapValue(Arena* arena, const MapKey& map_key) {
-  return VisitMapKey(map_key, *MutableMap(),
-                     [arena](auto& map, const auto& key) {
-                       return map.EraseImpl(arena, key);
-                     });
-}
-
 void MapFieldBase::ClearMapNoSync() {
   GetMapRaw().ClearTable(arena(), /*reset=*/true);
 }
 
-template <bool kIsMutable>
-void MapFieldBase::SetMapIteratorValue(
-    MapIteratorBase<kIsMutable>* map_iter) const {
-  if (map_iter->iter_.Equals(UntypedMapBase::EndIterator())) return;
-
-  const UntypedMapBase& map = *map_iter->iter_.m_;
-  NodeBase* node = map_iter->iter_.node_;
-  auto& key = map_iter->key_;
-  map.VisitKey(node,
-               absl::Overload{
-                   [&](const std::string* v) { key.val_.string_value = *v; },
-                   [&](const auto* v) {
-                     // Memcpy the scalar into the union.
-                     memcpy(static_cast<void*>(&key.val_), v, sizeof(*v));
-                   },
-               });
-  map_iter->value_.SetValue(map.GetVoidValue(node));
-}
-
-bool MapFieldBase::LookupMapValueNoSync(const MapKey& map_key,
-                                        MapValueConstRef* val) const {
-  auto& map = GetMapRaw();
-  if (map.empty()) return false;
-
-  return VisitMapKey(map_key, map, [&](auto& map, const auto& key) {
-    auto res = map.FindHelper(key);
-    if (res.node == nullptr) {
-      return false;
-    }
-    if (val != nullptr) {
-      val->SetValue(map.GetVoidValue(res.node));
-    }
-    return true;
-  });
-}
-
-void MapFieldBase::MapBegin(MapIterator* map_iter) const {
-  map_iter->iter_ = GetMap().begin();
-  SetMapIteratorValue(map_iter);
-}
-
-void MapFieldBase::MapEnd(MapIterator* map_iter) const {
-  map_iter->iter_ = UntypedMapBase::EndIterator();
-}
-
-void MapFieldBase::ConstMapBegin(ConstMapIterator* map_iter) const {
-  map_iter->iter_ = GetMap().begin();
-  SetMapIteratorValue(map_iter);
-}
-
-void MapFieldBase::ConstMapEnd(ConstMapIterator* map_iter) const {
-  map_iter->iter_ = UntypedMapBase::EndIterator();
-}
-
-template <bool kIsMutable>
-bool MapFieldBase::EqualIterator(const MapIteratorBase<kIsMutable>& a,
-                                 const MapIteratorBase<kIsMutable>& b) const {
-  return a.iter_.Equals(b.iter_);
-}
-
-template <bool kIsMutable>
-void MapFieldBase::IncreaseIterator(
-    MapIteratorBase<kIsMutable>* map_iter) const {
-  map_iter->iter_.PlusPlus();
-  SetMapIteratorValue(map_iter);
-}
-
-template <bool kIsMutable>
-void MapFieldBase::CopyIterator(
-    MapIteratorBase<kIsMutable>* this_iter,
-    const MapIteratorBase<kIsMutable>& that_iter) const {
-  this_iter->iter_ = that_iter.iter_;
-  this_iter->key_.SetType(that_iter.key_.type());
-  // MapValueRef::type() fails when containing data is null. However, if
-  // this_iter points to MapEnd, data can be null.
-  this_iter->value_.SetType(
-      static_cast<FieldDescriptor::CppType>(that_iter.value_.type_));
-  SetMapIteratorValue(this_iter);
-}
-
 const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const {
   ConstAccess();
   return SyncRepeatedFieldWithMap(false);
@@ -340,21 +234,22 @@
   RepeatedPtrField<Message>& rep = payload().repeated_field();
   rep.Clear();
 
-  ConstMapIterator it(this, descriptor);
-  ConstMapIterator end(this, descriptor);
-
+  GenericConstMapRef::iterator it;
+  it.key_type_ = descriptor->map_key()->cpp_type();
+  it.value_type_ = descriptor->map_value()->cpp_type();
   it.iter_ = GetMapRaw().begin();
-  SetMapIteratorValue(&it);
+
+  GenericConstMapRef::iterator end;
   end.iter_ = UntypedMapBase::EndIterator();
 
   Arena* arena = this->arena();
-  for (; !EqualIterator(it, end); IncreaseIterator(&it)) {
+  for (; it != end; ++it) {
     Message* new_entry = reinterpret_cast<Message*>(
         rep.AddInternal(arena, [prototype](Arena* arena, void*& ptr) {
           ptr = prototype->New(arena);
         }));
 
-    const MapKey& map_key = it.GetKey();
+    MapKey map_key = it->key();
     switch (key_des->cpp_type()) {
       case FieldDescriptor::CPPTYPE_STRING:
         reflection->SetString(new_entry, key_des,
@@ -379,7 +274,7 @@
         Unreachable();
     }
 
-    const MapValueConstRef& map_val = it.GetValueRef();
+    MapValueConstRef map_val = it->value();
     switch (val_des->cpp_type()) {
       case FieldDescriptor::CPPTYPE_STRING:
         reflection->SetString(new_entry, val_des,
@@ -450,6 +345,15 @@
   const FieldDescriptor* key_des = descriptor->map_key();
   const FieldDescriptor* val_des = descriptor->map_value();
 
+  GenericMapRef map_ref;
+  map_ref.key_type_ = descriptor->map_key()->cpp_type();
+  map_ref.value_type_ = descriptor->map_value()->cpp_type();
+  map_ref.map_ = &GetMapRaw();
+  if (descriptor->map_value()->message_type()) {
+    map_ref.value_class_data_ =
+        GetClassData(GetMapEntryValuePrototype(*prototype));
+  }
+
   for (const Message& elem : rep) {
     // MapKey type will be set later.
     Reflection::ScratchSpace map_key_scratch_space;
@@ -478,9 +382,7 @@
         Unreachable();
     }
 
-    MapValueRef map_val;
-    map_val.SetType(val_des->cpp_type());
-    InsertOrLookupMapValueNoSync(map_key, &map_val);
+    MapValueRef map_val = map_ref.try_emplace(map_key).value().iter->value();
 
     switch (val_des->cpp_type()) {
 #define HANDLE_TYPE(CPPTYPE, METHOD)                                    \
@@ -520,78 +422,212 @@
   SetMapDirty();
 }
 
-int MapFieldBase::size() const { return GetMap().size(); }
-
-bool MapFieldBase::InsertOrLookupMapValue(const MapKey& map_key,
-                                          MapValueRef* val) {
-  SyncMapWithRepeatedField();
-  SetMapDirty();
-  return InsertOrLookupMapValueNoSync(map_key, val);
-}
-
 void MapFieldBase::ReflectionPayload::Swap(ReflectionPayload& other) {
   repeated_field().Swap(&other.repeated_field());
   SwapRelaxed(state_, other.state_);
 }
 
+MapKey MapIteratorEntry::key() const {
+  return MapConstIteratorEntry(*this).key();
+}
+
+MapValueRef MapIteratorEntry::value() const {
+  MapValueRef value;
+  value.SetType(static_cast<FieldDescriptor::CppType>(value_type_));
+  value.SetValue(iter_.m_->GetVoidValue(iter_.node_));
+  return value;
+}
+
+MapKey MapConstIteratorEntry::key() const {
+  MapKey key;
+  key.SetType(static_cast<FieldDescriptor::CppType>(key_type_));
+  iter_.m_->VisitKey(
+      iter_.node_,
+      absl::Overload{
+          [&](const std::string* v) { key.val_.string_value = *v; },
+          [&](const auto* v) {
+            // Memcpy the scalar into the union.
+            memcpy(static_cast<void*>(&key.val_), v, sizeof(*v));
+          },
+      });
+  return key;
+}
+
+MapValueConstRef MapConstIteratorEntry::value() const {
+  MapValueConstRef value;
+  value.SetType(static_cast<FieldDescriptor::CppType>(value_type_));
+  value.SetValue(iter_.m_->GetVoidValue(iter_.node_));
+  return value;
+}
+
+static bool IsCompatibleKey(uint8_t expected_key_cpp_type, const MapKey& key) {
+  if (!key.is_initialized()) return false;
+  return key.type() ==
+         static_cast<FieldDescriptor::CppType>(expected_key_cpp_type);
+}
+
 }  // namespace internal
 
-template <bool kIsMutable>
-MapIteratorBase<kIsMutable>::MapIteratorBase(MessageT* message,
-                                             const FieldDescriptor* field) {
-  const Reflection* reflection = message->GetReflection();
-  if constexpr (kIsMutable) {
-    map_ = reflection->MutableMapData(message, field);
-  } else {
-    map_ = reflection->GetMapData(*message, field);
+GenericMapRef::iterator GenericMapRef::begin() const {
+  iterator iter;
+  iter.key_type_ = key_type_;
+  iter.value_type_ = value_type_;
+  iter.iter_ = map_->begin();
+  return iter;
+}
+
+GenericMapRef::iterator GenericMapRef::end() const {
+  iterator iter;
+  iter.iter_ = internal::UntypedMapBase::EndIterator();
+  return iter;
+}
+
+size_t GenericMapRef::size() const { return map_->size(); }
+
+bool GenericMapRef::empty() const { return size() == 0; }
+
+bool GenericMapRef::contains(const MapKey& key) const {
+  return find(key) != end();
+}
+
+GenericMapRef::iterator GenericMapRef::find(const MapKey& key) const {
+  auto it = GenericConstMapRef(*this).find(key);
+  iterator res;
+  res.key_type_ = key_type_;
+  res.value_type_ = value_type_;
+  res.iter_ = it.iter_;
+  return res;
+}
+
+absl::Status GenericMapRef::assign(const GenericConstMapRef& other) const {
+  auto status = GenericConstMapRef::CheckSameType(*this, other);
+  if (!status.ok()) return status;
+  if (map_ == other.map_) return absl::OkStatus();
+  clear();
+  map_->UntypedMergeFrom(map_->arena(), *other.map_);
+  return absl::OkStatus();
+}
+
+absl::Status GenericMapRef::swap(const GenericMapRef& other) const {
+  auto status = GenericConstMapRef::CheckSameType(*this, other);
+  if (!status.ok()) return status;
+  map_->UntypedSwap(map_->arena(), *other.map_, other.map_->arena());
+  return absl::OkStatus();
+}
+
+void GenericMapRef::clear() const {
+  map_->ClearTable(map_->arena(), /*reset=*/true);
+}
+
+size_t GenericMapRef::erase(const MapKey& key) const {
+  if (!internal::IsCompatibleKey(key_type_, key)) return 0;
+  return internal::VisitMapKey(key, *map_, [](auto& map, const auto& key) {
+    return map.EraseImpl(map.arena(), key) ? 1 : 0;
+  });
+}
+
+absl::StatusOr<GenericMapRef::InsertResult> GenericMapRef::try_emplace(
+    const MapKey& key) const {
+  if (!internal::IsCompatibleKey(key_type_, key)) {
+    return absl::InvalidArgumentError(
+        "MapKey is uninitialized or key type mismatch.");
   }
-  key_.SetType(field->message_type()->map_key()->cpp_type());
-  value_.SetType(field->message_type()->map_value()->cpp_type());
+
+  InsertResult res;
+  res.iter.key_type_ = key_type_;
+  res.iter.value_type_ = value_type_;
+  res.iter.iter_.m_ = map_;
+
+  if (!map_->empty()) {
+    auto find_res = internal::VisitMapKey(
+        key, *map_,
+        [&](auto& map, const auto& key) { return map.FindHelper(key); });
+    if (find_res.node != nullptr) {
+      res.iter.iter_.node_ = find_res.node;
+      res.iter.iter_.bucket_index_ = find_res.bucket;
+      res.inserted = false;
+      return res;
+    }
+  }
+
+  Arena* arena = map_->arena();
+  auto* node = map_->AllocNode(arena);
+  map_->VisitValue(node, [&](auto* v) { InitializeKeyValue(v); });
+  res.inserted = true;
+  res.iter.iter_.node_ = node;
+  res.iter.iter_.bucket_index_ = 0;
+
+  internal::VisitMapKey(key, *map_, [&](auto& map, const auto& key) {
+    InitializeKeyValue(map.GetKey(node), key);
+    // Note: If we see enough usage of this we might want to refactor to avoid a
+    // second lookup here.
+    map.InsertOrReplaceNode(
+        arena,
+        static_cast<typename std::decay_t<decltype(map)>::KeyNode*>(node));
+  });
+
+  return res;
 }
 
-template <bool kIsMutable>
-MapIteratorBase<kIsMutable>& MapIteratorBase<kIsMutable>::operator=(
-    const MapIteratorBase& other) {
-  map_ = other.map_;
-  map_->CopyIterator(this, other);
-  return *this;
+absl::Status GenericConstMapRef::CheckSameType(const GenericConstMapRef& a,
+                                               const GenericConstMapRef& b) {
+  if (a.key_type_ != b.key_type_ || a.value_type_ != b.value_type_) {
+    return absl::InvalidArgumentError("Map key or value CppType mismatch.");
+  }
+  if (a.value_class_data_ != b.value_class_data_) {
+    return absl::InvalidArgumentError("Map value message prototype mismatch.");
+  }
+  return absl::OkStatus();
 }
 
-template <bool kIsMutable>
-bool MapIteratorBase<kIsMutable>::operator==(
-    const MapIteratorBase<kIsMutable>& other) const {
-  return map_->EqualIterator(*this, other);
+GenericConstMapRef::iterator GenericConstMapRef::begin() const {
+  iterator iter;
+  iter.key_type_ = key_type_;
+  iter.value_type_ = value_type_;
+  iter.iter_ = map_->begin();
+  return iter;
 }
 
-template <bool kIsMutable>
-typename MapIteratorBase<kIsMutable>::DerivedIterator&
-MapIteratorBase<kIsMutable>::operator++() {
-  map_->IncreaseIterator(this);
-  return static_cast<DerivedIterator&>(*this);
+GenericConstMapRef::iterator GenericConstMapRef::end() const {
+  iterator iter;
+  iter.iter_ = internal::UntypedMapBase::EndIterator();
+  return iter;
 }
 
-template <bool kIsMutable>
-typename MapIteratorBase<kIsMutable>::DerivedIterator
-MapIteratorBase<kIsMutable>::operator++(int) {
-  // iter_ is copied from Map<...>::iterator, no need to
-  // copy from its self again. Use the same implementation
-  // with operator++()
-  map_->IncreaseIterator(this);
-  return *static_cast<DerivedIterator*>(this);
+size_t GenericConstMapRef::size() const { return map_->size(); }
+
+bool GenericConstMapRef::empty() const { return size() == 0; }
+
+bool GenericConstMapRef::contains(const MapKey& key) const {
+  return find(key) != end();
 }
 
-template <bool kIsMutable>
-MapIteratorBase<kIsMutable>::MapIteratorBase(MapFieldBase* map,
-                                             const Descriptor* descriptor) {
-  map_ = map;
-  key_.SetType(descriptor->map_key()->cpp_type());
-  value_.SetType(descriptor->map_value()->cpp_type());
-}
+GenericConstMapRef::iterator GenericConstMapRef::find(
+    const MapKey& map_key) const {
+  iterator res;
+  res.key_type_ = key_type_;
+  res.value_type_ = value_type_;
 
-template class PROTOBUF_EXPORT_TEMPLATE_DEFINE
-    MapIteratorBase</*kIsMutable=*/false>;
-template class PROTOBUF_EXPORT_TEMPLATE_DEFINE
-    MapIteratorBase</*kIsMutable=*/true>;
+  if (map_->empty() || !internal::IsCompatibleKey(key_type_, map_key)) {
+    res.iter_ = internal::UntypedMapBase::EndIterator();
+    return res;
+  }
+
+  res.iter_ =
+      internal::VisitMapKey(map_key, *map_, [&](auto& map, const auto& key) {
+        auto res = map.FindHelper(key);
+        if (res.node == nullptr) {
+          return internal::UntypedMapBase::EndIterator();
+        }
+        internal::UntypedMapIterator iter;
+        iter.node_ = res.node;
+        iter.bucket_index_ = res.bucket;
+        iter.m_ = &map;
+        return iter;
+      });
+
+  return res;
+}
 
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index cf8a1bb..f6d6db3 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -11,12 +11,16 @@
 #include <atomic>
 #include <cstddef>
 #include <cstdint>
+#include <iterator>
 #include <string>
 #include <type_traits>
 #include <utility>
 
+#include "absl/base/attributes.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
 #include "google/protobuf/arena.h"
@@ -45,12 +49,12 @@
 namespace google {
 namespace protobuf {
 class DynamicMessage;
-template <bool>
-class MapIteratorBase;
-class ConstMapIterator;
-class MapIterator;
 
 namespace internal {
+class ABSL_ATTRIBUTE_VIEW MapConstIterator;
+class ABSL_ATTRIBUTE_VIEW MapConstIteratorEntry;
+class ABSL_ATTRIBUTE_VIEW MapIterator;
+class ABSL_ATTRIBUTE_VIEW MapIteratorEntry;
 class MapFieldBase;
 }
 
@@ -74,12 +78,14 @@
 // MapKey is an union type for representing any possible map key. For strings,
 // map key does not own the underlying data. It is up to the caller to ensure
 // any supplied strings outlive any instance of this class.
-class PROTOBUF_EXPORT MapKey {
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapKey {
  public:
   MapKey() = default;
   MapKey(const MapKey&) = default;
   MapKey& operator=(const MapKey&) = default;
 
+  bool is_initialized() const { return type_ != FieldDescriptor::CppType(); }
+
   FieldDescriptor::CppType type() const {
     if (type_ == FieldDescriptor::CppType()) {
       ABSL_LOG(FATAL) << "Protocol Buffer map usage error:\n"
@@ -233,8 +239,7 @@
   template <typename K, typename V>
   friend class internal::TypeDefinedMapFieldBase;
   friend class internal::MapFieldBase;
-  template <bool>
-  friend class MapIteratorBase;
+  friend internal::MapConstIteratorEntry;
 
   template <typename H>
   friend auto AbslHashValue(H state, const MapKey& key) {
@@ -279,13 +284,6 @@
 
 namespace internal {
 
-template <>
-struct is_internal_map_key_type<MapKey> : std::true_type {};
-
-}  // namespace internal
-
-namespace internal {
-
 class ContendedMapCleanTest;
 class GeneratedMessageReflection;
 class MapFieldAccessor;
@@ -340,40 +338,14 @@
   PROTOBUF_FUTURE_ADD_EARLY_NODISCARD RepeatedPtrFieldBase*
   MutableRepeatedField();
 
-  PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool ContainsMapKey(
-      const MapKey& map_key) const {
-    return LookupMapValue(map_key, static_cast<MapValueConstRef*>(nullptr));
-  }
-  PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool LookupMapValue(
-      const MapKey& map_key, MapValueConstRef* val) const {
-    SyncMapWithRepeatedField();
-    return LookupMapValueNoSync(map_key, val);
-  }
-  bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
-
-  bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val);
-
   // Returns whether changes to the map are reflected in the repeated field.
   PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool IsRepeatedFieldValid() const;
   // Insures operations after won't get executed before calling this.
   PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool IsMapValid() const;
-  bool DeleteMapValue(Arena* arena, const MapKey& map_key);
   void MergeFrom(Arena* arena, const MapFieldBase& other);
   void Swap(Arena* arena, MapFieldBase* other, Arena* other_arena);
   void InternalSwap(MapFieldBase* other);
-  // Sync Map with repeated field and returns the size of map.
-  PROTOBUF_FUTURE_ADD_EARLY_NODISCARD int size() const;
   void Clear();
-  template <bool kIsMutable>
-  void SetMapIteratorValue(MapIteratorBase<kIsMutable>* map_iter) const;
-
-  void MapBegin(MapIterator* map_iter) const;
-  void MapEnd(MapIterator* map_iter) const;
-  void ConstMapBegin(ConstMapIterator* map_iter) const;
-  void ConstMapEnd(ConstMapIterator* map_iter) const;
-  template <bool kIsMutable>
-  bool EqualIterator(const MapIteratorBase<kIsMutable>& a,
-                     const MapIteratorBase<kIsMutable>& b) const;
 
   // Returns the number of bytes used by the repeated field, excluding
   // sizeof(*this)
@@ -416,8 +388,6 @@
   // Provides derived class the access to repeated field.
   void* MutableRepeatedPtrField() const;
 
-  bool InsertOrLookupMapValueNoSync(const MapKey& map_key, MapValueRef* val);
-
   // Support thread sanitizer (tsan) by making const / mutable races
   // more apparent.  If one thread calls MutableAccess() while another
   // thread calls either ConstAccess() or MutableAccess(), on the same
@@ -501,41 +471,6 @@
   friend class google::protobuf::Reflection;
   friend class google::protobuf::DynamicMessage;
 
-  template <typename T, typename... U>
-  void InitializeKeyValue(T* v, const U&... init) {
-    ::new (static_cast<void*>(v)) T(init...);
-    if constexpr (std::is_same_v<std::string, T>) {
-      if (arena() != nullptr) {
-        arena()->OwnDestructor(v);
-      }
-    }
-  }
-
-  void InitializeKeyValue(MessageLite* msg) {
-    GetClassData(GetMapEntryValuePrototype(*GetPrototype()))
-        ->PlacementNew(msg, arena());
-  }
-
-  // Virtual helper methods for MapIterator. MapIterator doesn't have the
-  // type helper for key and value. Call these help methods to deal with
-  // different types. Real helper methods are implemented in
-  // TypeDefinedMapFieldBase.
-  template <bool>
-  friend class google::protobuf::MapIteratorBase;
-  friend class google::protobuf::MapIterator;
-
-  // Copy the map<...>::iterator from other_iterator to
-  // this_iterator.
-  template <bool kIsMutable>
-  void CopyIterator(MapIteratorBase<kIsMutable>* this_iter,
-                    const MapIteratorBase<kIsMutable>& that_iter) const;
-
-  // IncreaseIterator() is called by operator++() of MapIterator only.
-  // It implements the ++ operator of MapIterator.
-  template <bool kIsMutable>
-  void IncreaseIterator(MapIteratorBase<kIsMutable>* map_iter) const;
-
-  bool LookupMapValueNoSync(const MapKey& map_key, MapValueConstRef* val) const;
   static ReflectionPayload* ToPayload(const void* p) {
     ABSL_DCHECK(IsPayload(p));
     auto* res = reinterpret_cast<ReflectionPayload*>(
@@ -687,7 +622,7 @@
 
 // MapValueConstRef points to a map value. Users can NOT modify
 // the map value.
-class PROTOBUF_EXPORT MapValueConstRef {
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapValueConstRef {
  public:
   MapValueConstRef() : data_(nullptr), type_() {}
 
@@ -751,37 +686,27 @@
   }
 
  protected:
+  friend internal::MapConstIteratorEntry;
+  friend internal::MapIteratorEntry;
+
+  void SetType(FieldDescriptor::CppType type) { type_ = type; }
+  void SetValue(const void* val) {
+    ABSL_DCHECK_NE(static_cast<int>(type_), 0);
+    data_ = const_cast<void*>(val);
+  }
+
   // data_ point to a map value. MapValueConstRef does not
   // own this value.
   void* data_;
   // type_ is 0 or a valid FieldDescriptor::CppType.
   // Use "CppType()" to indicate zero.
-  FieldDescriptor::CppType type_;
-
- private:
-  template <auto* kGlobals, typename K, typename V>
-  friend class internal::MapField;
-  template <typename K, typename V>
-  friend class internal::TypeDefinedMapFieldBase;
-  template <bool>
-  friend class google::protobuf::MapIteratorBase;
-  friend class Reflection;
-  friend class internal::MapFieldBase;
-
-  void SetValueOrCopy(const void* val) { SetValue(val); }
-  void SetValueOrCopy(const MapValueConstRef* val) { CopyFrom(*val); }
-
-  void SetType(FieldDescriptor::CppType type) { type_ = type; }
-  void SetValue(const void* val) { data_ = const_cast<void*>(val); }
-  void CopyFrom(const MapValueConstRef& other) {
-    type_ = other.type_;
-    data_ = other.data_;
-  }
+  FieldDescriptor::CppType type_{};
 };
 
 // MapValueRef points to a map value. Users are able to modify
 // the map value.
-class PROTOBUF_EXPORT MapValueRef final : public MapValueConstRef {
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapValueRef final
+    : public MapValueConstRef {
  public:
   MapValueRef() = default;
 
@@ -828,104 +753,326 @@
                "MapValueRef::MutableMessageValue");
     return reinterpret_cast<Message*>(data_);
   }
+
+ private:
+  friend internal::MapIteratorEntry;
 };
 
 #undef TYPE_CHECK
 
-template <bool kIsMutable>
-class MapIteratorBase {
-  using MessageT =
-      std::conditional_t<kIsMutable, google::protobuf::Message, const google::protobuf::Message>;
-  using MapFieldBase = std::conditional_t<kIsMutable, internal::MapFieldBase,
-                                          const internal::MapFieldBase>;
-  using ValueRef =
-      std::conditional_t<kIsMutable, MapValueRef, MapValueConstRef>;
-  using DerivedIterator =
-      std::conditional_t<kIsMutable, MapIterator, ConstMapIterator>;
+namespace internal {
 
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapIteratorEntry final {
  public:
-  MapIteratorBase(MessageT* message, const FieldDescriptor* field);
-  MapIteratorBase(const MapIteratorBase& other) { *this = other; }
+  using key_type = MapKey;
+  using mapped_type = MapValueRef;
 
-  MapIteratorBase& operator=(const MapIteratorBase& other);
+  MapIteratorEntry(const MapIteratorEntry&) = default;
+  MapIteratorEntry& operator=(const MapIteratorEntry&) = default;
 
-  bool operator==(const MapIteratorBase& other) const;
-  friend bool operator!=(const MapIteratorBase& a, const MapIteratorBase& b) {
+  MapKey key() const;
+  MapValueRef value() const;
+
+ private:
+  friend MapIterator;
+  friend MapConstIteratorEntry;
+
+  MapIteratorEntry() = default;
+
+  uint8_t key_type_{};
+  uint8_t value_type_{};
+  internal::UntypedMapIterator iter_{};
+};
+
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapIterator final {
+ public:
+  using iterator_category = std::input_iterator_tag;
+  using iterator_concept = std::forward_iterator_tag;
+  using value_type = MapIteratorEntry;
+  using difference_type = ptrdiff_t;
+  using pointer = const value_type*;
+  using reference = value_type;
+  using key_type = value_type::key_type;
+  using mapped_type = value_type::mapped_type;
+
+  MapIterator() = default;
+  MapIterator(const MapIterator&) = default;
+  MapIterator& operator=(const MapIterator&) = default;
+
+  value_type operator*() const {
+    ABSL_CHECK(!iter_.Equals(internal::UntypedMapBase::EndIterator()))
+        << "Can't deref the end iterator";
+
+    value_type res;
+    res.key_type_ = key_type_;
+    res.value_type_ = value_type_;
+    res.iter_ = iter_;
+    return res;
+  }
+
+  auto operator->() const {
+    struct ABSL_ATTRIBUTE_VIEW ArrowProxy {
+      value_type value;
+      const value_type* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+        return &value;
+      }
+    };
+    return ArrowProxy{**this};
+  }
+
+  MapIterator& operator++() {
+    iter_.PlusPlus();
+    return *this;
+  }
+  MapIterator operator++(int) {
+    auto copy = *this;
+    iter_.PlusPlus();
+    return copy;
+  }
+
+  friend bool operator==(MapIterator a, MapIterator b) {
+    return a.iter_.Equals(b.iter_);
+  }
+  friend bool operator!=(MapIterator a, MapIterator b) { return !(a == b); }
+
+ private:
+  friend GenericMapRef;
+  friend MapConstIterator;
+
+  uint8_t key_type_{};
+  uint8_t value_type_{};
+  internal::UntypedMapIterator iter_{};
+};
+
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapConstIteratorEntry final {
+ public:
+  using key_type = MapKey;
+  using mapped_type = MapValueConstRef;
+
+  MapConstIteratorEntry(const MapConstIteratorEntry&) = default;
+  MapConstIteratorEntry& operator=(const MapConstIteratorEntry&) = default;
+  MapConstIteratorEntry(const MapIteratorEntry& entry)  // NOLINT
+      : key_type_(entry.key_type_),
+        value_type_(entry.value_type_),
+        iter_(entry.iter_) {}
+
+  MapKey key() const;
+  MapValueConstRef value() const;
+
+ private:
+  friend MapConstIterator;
+
+  MapConstIteratorEntry() = default;
+
+  uint8_t key_type_{};
+  uint8_t value_type_{};
+  internal::UntypedMapIterator iter_{};
+};
+
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapConstIterator final {
+ public:
+  using iterator_category = std::input_iterator_tag;
+  using iterator_concept = std::forward_iterator_tag;
+  using value_type = MapConstIteratorEntry;
+  using difference_type = ptrdiff_t;
+  using pointer = const value_type*;
+  using reference = value_type;
+  using key_type = value_type::key_type;
+  using mapped_type = value_type::mapped_type;
+
+  MapConstIterator() = default;
+  MapConstIterator(const MapConstIterator&) = default;
+  MapConstIterator& operator=(const MapConstIterator&) = default;
+  MapConstIterator(MapIterator it)  // NOLINT
+      : key_type_(it.key_type_), value_type_(it.value_type_), iter_(it.iter_) {}
+
+  value_type operator*() const {
+    ABSL_CHECK(!iter_.Equals(internal::UntypedMapBase::EndIterator()))
+        << "Can't deref the end iterator";
+
+    value_type res;
+    res.key_type_ = key_type_;
+    res.value_type_ = value_type_;
+    res.iter_ = iter_;
+    return res;
+  }
+
+  auto operator->() const {
+    struct ABSL_ATTRIBUTE_VIEW ArrowProxy {
+      value_type value;
+      const value_type* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+        return &value;
+      }
+    };
+    return ArrowProxy{**this};
+  }
+
+  MapConstIterator& operator++() {
+    iter_.PlusPlus();
+    return *this;
+  }
+  MapConstIterator operator++(int) {
+    auto copy = *this;
+    iter_.PlusPlus();
+    return copy;
+  }
+
+  friend bool operator==(MapConstIterator a, MapConstIterator b) {
+    return a.iter_.Equals(b.iter_);
+  }
+  friend bool operator!=(MapConstIterator a, MapConstIterator b) {
     return !(a == b);
   }
 
-  DerivedIterator& operator++();
-  DerivedIterator operator++(int);
-
-  const MapKey& GetKey() { return key_; }
-  const ValueRef& GetValueRef() { return value_; }
-
- protected:
-  template <typename Key, typename T>
-  friend class internal::TypeDefinedMapFieldBase;
-  template <auto* kGlobals, typename Key, typename T>
-  friend class internal::MapField;
-  friend class internal::MapFieldBase;
-
-  MapIteratorBase(MapFieldBase* map, const Descriptor* descriptor);
-
-  internal::UntypedMapIterator iter_;
-  // Point to a MapField to call helper methods implemented in MapField.
-  // MapIterator does not own this object.
-  MapFieldBase* map_;
-  MapKey key_;
-  ValueRef value_;
-};
-
-extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
-    MapIteratorBase</*kIsMutable=*/false>;
-extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE
-    MapIteratorBase</*kIsMutable=*/true>;
-
-class PROTOBUF_EXPORT ConstMapIterator final
-    : public MapIteratorBase</*kIsMutable=*/false> {
-  friend class internal::MapFieldBase;
-  template <typename MessageT>
-  friend struct internal::MapDynamicFieldInfo;
-
- public:
-  ConstMapIterator(const google::protobuf::Message* message, const FieldDescriptor* field)
-      : MapIteratorBase(message, field) {}
-
  private:
-  ConstMapIterator(const internal::MapFieldBase* map,
-                   const Descriptor* descriptor)
-      : MapIteratorBase(map, descriptor) {}
+  friend GenericConstMapRef;
+  friend GenericMapRef;
+  friend internal::MapFieldBase;
+
+  uint8_t key_type_{};
+  uint8_t value_type_{};
+  internal::UntypedMapIterator iter_{};
 };
 
-class PROTOBUF_EXPORT MapIterator final
-    : public MapIteratorBase</*kIsMutable=*/true> {
-  friend class internal::MapFieldBase;
-  template <typename MessageT>
-  friend struct internal::MapDynamicFieldInfo;
-
- public:
-  MapIterator(google::protobuf::Message* message, const FieldDescriptor* field)
-      : MapIteratorBase(message, field) {}
-
-  MapValueRef* MutableValueRef() {
-    map_->SetMapDirty();
-    return &value_;
-  }
-
- private:
-  MapIterator(internal::MapFieldBase* map, const Descriptor* descriptor)
-      : MapIteratorBase(map, descriptor) {}
-};
-
-namespace internal {
-template <>
-struct is_internal_map_value_type<class MapValueConstRef> : std::true_type {};
-template <>
-struct is_internal_map_value_type<class MapValueRef> : std::true_type {};
-
 }  // namespace internal
 
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW GenericMapRef final {
+ public:
+  using iterator = internal::MapIterator;
+  using const_iterator = internal::MapConstIterator;
+  using value_type = iterator::value_type;
+  using key_type = iterator::key_type;
+  using mapped_type = iterator::mapped_type;
+
+  GenericMapRef(const GenericMapRef&) = default;
+
+  // Deleted to prevent confusion as to whether the assignment is shallow or
+  // deep.
+  GenericMapRef& operator=(const GenericMapRef&) = delete;
+
+  iterator begin() const;
+  iterator end() const;
+  size_t size() const;
+  bool empty() const;
+  bool contains(const MapKey& key) const;
+  iterator find(const MapKey& key) const;
+
+  void clear() const;
+  size_t erase(const MapKey& key) const;
+
+  // These perform the operation on the underlying instances.
+  // They do not alter the handles themselves.
+  absl::Status assign(const GenericConstMapRef& other) const;
+  absl::Status swap(const GenericMapRef& other) const;
+
+  struct PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW InsertResult {
+    internal::MapIterator iter;
+    bool inserted;
+  };
+  absl::StatusOr<InsertResult> try_emplace(const MapKey& key) const;
+
+ private:
+  friend Reflection;
+  friend internal::MapFieldBase;
+  friend GenericConstMapRef;
+
+  GenericMapRef() = default;
+
+  template <typename T, typename... U>
+  void InitializeKeyValue(T* v, const U&... init) const {
+    ::new (static_cast<void*>(v)) T(init...);
+    if constexpr (std::is_same_v<std::string, T>) {
+      if (auto* a = map_->arena()) {
+        a->OwnDestructor(v);
+      }
+    }
+  }
+
+  void InitializeKeyValue(MessageLite* msg) const {
+    value_class_data_->PlacementNew(msg, map_->arena());
+  }
+
+  uint8_t key_type_{};
+  uint8_t value_type_{};
+  internal::UntypedMapBase* map_ = nullptr;
+  const internal::ClassData* value_class_data_ = nullptr;
+};
+
+class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW GenericConstMapRef final {
+ public:
+  using iterator = internal::MapConstIterator;
+  using const_iterator = iterator;
+  using value_type = iterator::value_type;
+  using key_type = iterator::key_type;
+  using mapped_type = iterator::mapped_type;
+
+  GenericConstMapRef(const GenericConstMapRef&) = default;
+  GenericConstMapRef& operator=(const GenericConstMapRef&) = default;
+  GenericConstMapRef(const GenericMapRef& mut)  // NOLINT
+      : key_type_(mut.key_type_),
+        value_type_(mut.value_type_),
+        map_(mut.map_),
+        value_class_data_(mut.value_class_data_) {}
+
+  iterator begin() const;
+  iterator end() const;
+  size_t size() const;
+  bool empty() const;
+  bool contains(const MapKey& key) const;
+  iterator find(const MapKey& key) const;
+
+ private:
+  friend Reflection;
+  friend GenericMapRef;
+
+  GenericConstMapRef() = default;
+
+  static absl::Status CheckSameType(const GenericConstMapRef& a,
+                                    const GenericConstMapRef& b);
+
+  uint8_t key_type_{};
+  uint8_t value_type_{};
+  const internal::UntypedMapBase* map_ = nullptr;
+  const internal::ClassData* value_class_data_ = nullptr;
+};
+
+// This class was never part of any public API (even though it was mistakenly
+// put in the public namespace).
+// We are replacing the old internal map reflection API with the new public one
+// and this class is going away. It is here for now to support the migration of
+// a friend project that is using the internal API.
+class [[deprecated(
+    "Legacy internal class. Use Reflection::GetMap instead.")]] PROTOBUF_EXPORT
+    ConstMapIterator final {
+ public:
+  MapKey GetKey() const { return it_->key(); }
+  MapValueConstRef GetValueRef() const { return it_->value(); }
+
+  ConstMapIterator& operator++() {
+    ++it_;
+    return *this;
+  }
+
+  PROTOBUF_IGNORE_DEPRECATION_START
+  friend bool operator==(ConstMapIterator a, ConstMapIterator b) {
+    return a.it_ == b.it_;
+  }
+  friend bool operator!=(ConstMapIterator a, ConstMapIterator b) {
+    return a.it_ != b.it_;
+  }
+  PROTOBUF_IGNORE_DEPRECATION_STOP
+
+ private:
+  friend Reflection;
+  ConstMapIterator() = default;
+  ConstMapIterator(internal::MapConstIterator it) : it_(it) {}  // NOLINT
+  internal::MapConstIterator it_;
+};
+
+// Expose this feature macro to users to let them know that the map reflection
+// API exists.
+#define PROTOBUF_HAS_MAP_REFLECTION_APIS 1
+
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index fc67c4f..922090a 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -446,7 +446,7 @@
   // This tests that `MapField` and all its base classes can be constant
   // initialized.
   PROTOBUF_CONSTINIT static MyMapField field;  // NOLINT
-  EXPECT_EQ(field.size(), 0);
+  EXPECT_EQ(field.GetMap().size(), 0);
 }
 
 TEST(MapFieldTest, MutableMapDoesNotAllocatePayload) {
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 23ab064..4c8d297 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -480,6 +480,13 @@
 }
 
 
+TEST(MapTest, MapReflection) {
+#if !defined(PROTOBUF_HAS_MAP_REFLECTION_APIS) || \
+    !PROTOBUF_HAS_MAP_REFLECTION_APIS
+  FAIL() << "Missing feature macro.";
+#endif
+}
+
 
 }  // namespace
 }  // namespace internal
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc
index e315221..947457f 100644
--- a/src/google/protobuf/map_test.inc
+++ b/src/google/protobuf/map_test.inc
@@ -17,11 +17,13 @@
 #include <algorithm>
 #include <cstddef>
 #include <cstdint>
+#include <iterator>
 #include <limits>
 #include <memory>
 #include <ostream>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
@@ -38,6 +40,7 @@
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
 #include "absl/log/globals.h"
+#include "absl/status/status_matchers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
@@ -70,7 +73,9 @@
 // Must be included last.
 #include "google/protobuf/port_def.inc"
 
+using ::absl_testing::StatusIs;
 using ::testing::ElementsAre;
+using ::testing::HasSubstr;
 using ::testing::IsEmpty;
 using ::testing::Pair;
 
@@ -1083,7 +1088,29 @@
 
     reflection_tester.ExpectMapFieldsSetViaReflection(rhs);
 
-      // Add an entry to make sure it is using the right arena.
+    (*rhs.mutable_map_int32_int32())[1234] = 1234;
+  }
+}
+
+TEST_F(MapImplTest, SwapFieldArenaMapReflection) {
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+
+  {
+    TestMap rhs;
+
+    {
+      Arena local_arena;
+      auto* lhs = Arena::Create<TestMap>(&local_arena);
+
+      reflection_tester.SetMapFieldsViaMapReflection(lhs);
+      reflection_tester.SwapMapsViaMapReflection(lhs, &rhs);
+
+      reflection_tester.ExpectClearViaReflection(*lhs);
+
+      (*lhs->mutable_map_int32_int32())[1234] = 1234;
+    }
+
+    reflection_tester.ExpectMapFieldsSetViaReflection(rhs);
     (*rhs.mutable_map_int32_int32())[1234] = 1234;
   }
 }
@@ -1127,22 +1154,21 @@
       auto* field = descriptor->field(i);
       if (!field->is_map()) continue;
 
-      ConstMapIterator it =
-          reflection_tester.ConstMapBegin(message, field->name());
-      ConstMapIterator end =
-          reflection_tester.ConstMapEnd(message, field->name());
+      GenericConstMapRef map_ref =
+          message->GetReflection()->GetMap(*message, field).value();
       // It's unordered, so search for it.
-      if (it == end) continue;
+      if (map_ref.empty()) continue;
+      auto it = map_ref.begin();
       auto next = it;
       ++next;
-      ASSERT_NE(next, end);
-      if (next.GetKey() < it.GetKey()) {
+      ASSERT_NE(next, map_ref.end());
+      if (next->key() < it->key()) {
         it = next;
       }
 
       EXPECT_EQ(reflection_tester.MapSize(*message, field->name()), 2);
-      reflection_tester.DeleteMapValueViaMapReflection(
-          message, field->name(), it.GetKey());
+      reflection_tester.DeleteMapValueViaMapReflection(message, field->name(),
+                                                       it->key());
       EXPECT_EQ(reflection_tester.MapSize(*message, field->name()), 1);
     }
 
@@ -1179,16 +1205,14 @@
       auto* field = descriptor->field(i);
       if (!field->is_map()) continue;
 
-      ConstMapIterator it =
-          reflection_tester.ConstMapBegin(message, field->name());
-      ConstMapIterator end =
-          reflection_tester.ConstMapEnd(message, field->name());
+      GenericConstMapRef map_ref =
+          message->GetReflection()->GetMap(*message, field).value();
 
-      while (it != end) {
+      for (auto it = map_ref.begin(); it != map_ref.end();) {
         auto next = it;
         ++next;
-        reflection_tester.DeleteMapValueViaMapReflection(
-            message, field->name(), it.GetKey());
+        reflection_tester.DeleteMapValueViaMapReflection(message, field->name(),
+                                                         it->key());
         it = next;
       }
       EXPECT_EQ(reflection_tester.MapSize(*message, field->name()), 0);
@@ -1198,67 +1222,101 @@
 
 TEST_F(MapImplTest, CopyAssignMapIterator) {
   TestMap message;
-  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  const auto* desc = message.descriptor();
+  const auto* field = desc->FindFieldByName("map_int32_int32");
+  MapReflectionTester reflection_tester(desc);
   reflection_tester.SetMapFieldsViaMapReflection(&message);
-  ConstMapIterator it1 =
-      reflection_tester.ConstMapBegin(&message, "map_int32_int32");
-  ConstMapIterator it2 =
-      reflection_tester.ConstMapEnd(&message, "map_int32_int32");
+  auto map = message.GetReflection()->GetMap(message, field).value();
+  auto it1 = map.begin();
+  auto it2 = map.end();
   it2 = it1;
-  EXPECT_EQ(it1.GetKey().GetInt32Value(), it2.GetKey().GetInt32Value());
+  EXPECT_EQ(it1->key().GetInt32Value(), it2->key().GetInt32Value());
 }
 
 class MapTestWithParams
-    : public testing::TestWithParam<std::tuple<bool, bool, bool>> {};
+    : public testing::TestWithParam<std::tuple<bool, bool, bool>> {
+ protected:
+  const Descriptor* descriptor_ = UNITTEST::TestMap::descriptor();
+  DynamicMessageFactory factory_;
+  std::unique_ptr<const Message> dyn_message_{
+      factory_.GetPrototype(descriptor_)->New()};
+  TestMap gen_message_;
+  Arena arena_;
+
+  Message* MakeMessage(bool in_arena) {
+    bool use_dynamic = std::get<0>(GetParam());
+    auto* prototype = use_dynamic ? dyn_message_.get() : &gen_message_;
+    return in_arena ? prototype->New(&arena_)
+                    : Arena::Create<std::unique_ptr<Message>>(&arena_,
+                                                              prototype->New())
+                          ->get();
+  }
+};
 
 INSTANTIATE_TEST_SUITE_P(MapTestWithParamsSuite, MapTestWithParams,
                          testing::Combine(testing::Bool(), testing::Bool(),
                                           testing::Bool()));
 
 TEST_P(MapTestWithParams, SwapMapsFieldsViaReflection) {
-  auto* descriptor = UNITTEST::TestMap::descriptor();
   auto [use_dynamic, lhs_arena, rhs_arena] = GetParam();
-
-  DynamicMessageFactory factory;
-  std::unique_ptr<const Message> dyn_message(
-      factory.GetPrototype(descriptor)->New());
-  TestMap gen_message;
-  Arena arena;
-
-  std::vector<const FieldDescriptor*> fields;
-  for (int i = 0; i < descriptor->field_count(); ++i) {
-    fields.push_back(descriptor->field(i));
-  }
-
-  const auto make = [&, use_dynamic = use_dynamic](bool in_arena) {
-    auto* prototype = use_dynamic ? dyn_message.get() : &gen_message;
-    return in_arena ? prototype->New(&arena)
-                    : Arena::Create<std::unique_ptr<Message>>(&arena,
-                                                              prototype->New())
-                          ->get();
-  };
-
-  auto* lhs = make(lhs_arena);
-  auto* rhs = make(rhs_arena);
-  MapReflectionTester reflection_tester(descriptor);
+  auto* lhs = MakeMessage(lhs_arena);
+  auto* rhs = MakeMessage(rhs_arena);
+  MapReflectionTester reflection_tester(descriptor_);
   reflection_tester.SetMapFieldsViaMapReflection(lhs);
 
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(lhs);
-  reflection_tester.ExpectClearViaReflectionIterator(rhs);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*lhs);
+  reflection_tester.ExpectClearViaReflectionIterator(*rhs);
+
+  std::vector<const FieldDescriptor*> fields;
+  for (int i = 0; i < descriptor_->field_count(); ++i) {
+    fields.push_back(descriptor_->field(i));
+  }
 
   lhs->GetReflection()->SwapFields(lhs, rhs, fields);
 
-  reflection_tester.ExpectClearViaReflectionIterator(lhs);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(rhs);
+  reflection_tester.ExpectClearViaReflectionIterator(*lhs);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*rhs);
 
   if (lhs_arena == rhs_arena) {
     // If they are the same arena, we can try the unsafe swap.
     lhs->GetReflection()->UnsafeArenaSwapFields(lhs, rhs, fields);
-    reflection_tester.ExpectClearViaReflectionIterator(rhs);
-    reflection_tester.ExpectMapFieldsSetViaReflectionIterator(lhs);
+    reflection_tester.ExpectClearViaReflectionIterator(*rhs);
+    reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*lhs);
   }
 }
 
+TEST_P(MapTestWithParams, SwapMapsViaMapReflection) {
+  auto [use_dynamic, lhs_arena, rhs_arena] = GetParam();
+  auto* lhs = MakeMessage(lhs_arena);
+  auto* rhs = MakeMessage(rhs_arena);
+  MapReflectionTester reflection_tester(descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(lhs);
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*lhs);
+  reflection_tester.ExpectClearViaReflectionIterator(*rhs);
+
+  reflection_tester.SwapMapsViaMapReflection(lhs, rhs);
+
+  reflection_tester.ExpectClearViaReflectionIterator(*lhs);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*rhs);
+}
+
+TEST_P(MapTestWithParams, AssignMapsViaMapReflection) {
+  auto [use_dynamic, lhs_arena, rhs_arena] = GetParam();
+  auto* src = MakeMessage(lhs_arena);
+  auto* dst = MakeMessage(rhs_arena);
+  MapReflectionTester reflection_tester(descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(src);
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src);
+  reflection_tester.ExpectClearViaReflectionIterator(*dst);
+
+  reflection_tester.AssignMapsViaMapReflection(dst, src);
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*dst);
+}
+
 class MapTestCodegenOrDynamic : public testing::TestWithParam<bool> {};
 
 INSTANTIATE_TEST_SUITE_P(MapTestCodegenOrDynamicSuite, MapTestCodegenOrDynamic,
@@ -1550,22 +1608,7 @@
   return result;
 }
 
-}  // namespace
-
-// This class is a friend, so no anonymous namespace.
-class MapFieldReflectionTest : public testing::Test {
- protected:
-  typedef FieldDescriptor FD;
-
-  int MapSize(const Reflection* reflection, const FieldDescriptor* field,
-              const Message& message) {
-    return reflection->MapSize(message, field);
-  }
-};
-
-namespace {
-
-TEST_F(MapFieldReflectionTest, RegularFields) {
+TEST(MapFieldReflectionTest, RegularFields) {
   TestMap message;
   const Reflection* refl = message.GetReflection();
   const Descriptor* desc = message.GetDescriptor();
@@ -1757,7 +1800,7 @@
   }
 }
 
-TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
+TEST(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) {
   TestMap message;
   const Reflection* refl = message.GetReflection();
   const Descriptor* desc = message.GetDescriptor();
@@ -2249,7 +2292,7 @@
   }
 }
 
-TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
+TEST(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
   // Set-up message content.
   TestMap m0, m1, m2;
   for (int i = 0; i < 10; ++i) {
@@ -2355,7 +2398,7 @@
   // TODO: add test for duplicated key
 }
 
-TEST_F(MapFieldReflectionTest, MapSizeWithDuplicatedKey) {
+TEST(MapFieldReflectionTest, MapSizeWithDuplicatedKey) {
   // Dynamic Message
   {
     DynamicMessageFactory factory;
@@ -2374,7 +2417,7 @@
     entry_reflection->SetInt32(entry2, key_field, 1);
 
     EXPECT_EQ(2, reflection->FieldSize(*message, field));
-    EXPECT_EQ(1, MapSize(reflection, field, *message));
+    EXPECT_EQ(1, reflection->GetMap(*message, field).value().size());
     EXPECT_EQ(2, reflection->FieldSize(*message, field));
   }
 
@@ -2394,11 +2437,11 @@
     entry_reflection->SetInt32(entry2, key_field, 1);
 
     EXPECT_EQ(2, reflection->FieldSize(message, field));
-    EXPECT_EQ(1, MapSize(reflection, field, message));
+    EXPECT_EQ(1, reflection->GetMap(message, field).value().size());
   }
 }
 
-TEST_F(MapFieldReflectionTest, UninitializedEntry) {
+TEST(MapFieldReflectionTest, UninitializedEntry) {
   UNITTEST::TestRequiredMessageMap message;
   const Reflection* reflection = message.GetReflection();
   const FieldDescriptor* field =
@@ -3508,7 +3551,91 @@
   MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
   reflection_tester.SetMapFieldsViaMapReflection(&message);
   reflection_tester.ExpectMapFieldsSetViaReflection(message);
-  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ClearViaMapReflection) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  reflection_tester.ExpectMapFieldsSetViaReflection(message);
+  reflection_tester.ClearMapFieldsViaMapReflection(&message);
+  reflection_tester.ExpectClearViaReflection(message);
+  reflection_tester.ExpectClearViaReflectionIterator(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, ModifyViaMapReflection) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  reflection_tester.ModifyMapFieldsViaReflection(&message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, SwapMapsViaMapReflection) {
+  UNITTEST::TestMap message1;
+  UNITTEST::TestMap message2;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message1);
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1);
+  reflection_tester.ExpectClearViaReflectionIterator(message2);
+
+  reflection_tester.SwapMapsViaMapReflection(&message1, &message2);
+
+  reflection_tester.ExpectClearViaReflectionIterator(message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message2);
+}
+
+TEST(GeneratedMapFieldReflectionTest, AssignMapsViaMapReflection) {
+  UNITTEST::TestMap src;
+  UNITTEST::TestMap dst;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&src);
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(src);
+  reflection_tester.ExpectClearViaReflectionIterator(dst);
+
+  reflection_tester.AssignMapsViaMapReflection(&dst, &src);
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(src);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(dst);
+}
+
+TEST(GeneratedMapFieldReflectionTest, EraseMapValuesViaMapReflectionIterator) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(&message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message);
+
+  reflection_tester.EraseMapValuesViaMapReflectionIterator(&message);
+  reflection_tester.ExpectClearViaReflection(message);
+  reflection_tester.ExpectClearViaReflectionIterator(message);
+}
+
+TEST(GeneratedMapFieldReflectionTest, InsertOrLookupMapValue) {
+  UNITTEST::TestMap message;
+  MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor());
+
+  MapKey key;
+  key.SetInt32Value(42);
+  MapValueRef val_ref;
+  EXPECT_TRUE(reflection_tester.InsertOrLookupMapValue(
+      &message, "map_int32_int32", key, &val_ref));
+  val_ref.SetInt32Value(100);
+
+  EXPECT_FALSE(reflection_tester.InsertOrLookupMapValue(
+      &message, "map_int32_int32", key, &val_ref));
+  EXPECT_EQ(val_ref.GetInt32Value(), 100);
+
+  MapValueConstRef const_val_ref;
+  EXPECT_TRUE(reflection_tester.LookupMapValue(message, "map_int32_int32", key,
+                                               &const_val_ref));
+  EXPECT_EQ(const_val_ref.GetInt32Value(), 100);
+
+  MapKey non_exist_key;
+  non_exist_key.SetInt32Value(999);
+  EXPECT_FALSE(reflection_tester.LookupMapValue(message, "map_int32_int32",
+                                                non_exist_key, &const_val_ref));
 }
 
 // Dynamic Message Test =============================================
@@ -3554,6 +3681,59 @@
   MapReflectionTester reflection_tester(map_descriptor_);
   reflection_tester.SetMapFieldsViaMapReflection(message.get());
   reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, ClearViaMapReflection) {
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflection(*message);
+
+  reflection_tester.ClearMapFieldsViaMapReflection(message.get());
+  reflection_tester.ExpectClearViaReflection(*message);
+  reflection_tester.ExpectClearViaReflectionIterator(*message);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, SwapMapsViaMapReflection) {
+  std::unique_ptr<Message> message1(map_prototype_->New());
+  std::unique_ptr<Message> message2(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message1);
+  reflection_tester.ExpectClearViaReflectionIterator(*message2);
+
+  reflection_tester.SwapMapsViaMapReflection(message1.get(), message2.get());
+
+  reflection_tester.ExpectClearViaReflectionIterator(*message1);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message2);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, AssignMapsViaMapReflection) {
+  std::unique_ptr<Message> src(map_prototype_->New());
+  std::unique_ptr<Message> dst(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(src.get());
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src);
+  reflection_tester.ExpectClearViaReflectionIterator(*dst);
+
+  reflection_tester.AssignMapsViaMapReflection(dst.get(), src.get());
+
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src);
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*dst);
+}
+
+TEST_F(MapFieldInDynamicMessageTest, EraseMapValuesViaMapReflectionIterator) {
+  std::unique_ptr<Message> message(map_prototype_->New());
+  MapReflectionTester reflection_tester(map_descriptor_);
+  reflection_tester.SetMapFieldsViaMapReflection(message.get());
+  reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message);
+
+  reflection_tester.EraseMapValuesViaMapReflectionIterator(message.get());
+  reflection_tester.ExpectClearViaReflection(*message);
+  reflection_tester.ExpectClearViaReflectionIterator(*message);
 }
 
 TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) {
@@ -3588,10 +3768,15 @@
   // Get value reference before serialization, so that we know the value is from
   // map.
   MapKey map_key;
-  MapValueRef map_val;
   map_key.SetInt32Value(0);
-  reflection_tester.GetMapValueViaMapReflection(
-      message.get(), "map_int32_foreign_message", map_key, &map_val);
+  auto insert_res =
+      message->GetReflection()
+          ->MutableMap(message.get(), message->GetDescriptor()->FindFieldByName(
+                                          "map_int32_foreign_message"))
+          .value()
+          .try_emplace(map_key)
+          .value();
+  MapValueRef map_val = insert_res.iter->value();
   Message* submsg = map_val.MutableMessageValue();
 
   // In previous implementation, calling SerializeToString will cause syncing
@@ -4434,6 +4619,196 @@
   EXPECT_EQ((*message.mutable_map_bytes())[1], "\xFF");
 }
 
+TEST_F(MapImplTest, FallibleMapReflectionApi) {
+  TestMap message;
+  const auto* desc = message.descriptor();
+  const auto* reflection = message.GetReflection();
+  const auto* map_i32_field = desc->FindFieldByName("map_int32_int32");
+  const auto* map_i64_field = desc->FindFieldByName("map_int64_int64");
+  TestAllTypes other_msg;
+  const auto* non_map_field =
+      other_msg.descriptor()->FindFieldByName("optional_int32");
+
+  // 1. GetMap / MutableMap with invalid arguments (replacing USAGE_CHECK
+  // crashes) Null field
+  EXPECT_THAT(reflection->GetMap(message, nullptr),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("FieldDescriptor is null")));
+  EXPECT_THAT(reflection->MutableMap(&message, nullptr),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("FieldDescriptor is null")));
+
+  // Null message pointer
+  EXPECT_THAT(reflection->MutableMap(nullptr, map_i32_field),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Message pointer is null")));
+
+  // Field is singular/repeated (not a map)
+  EXPECT_THAT(other_msg.GetReflection()->GetMap(other_msg, non_map_field),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("requires a map field")));
+  EXPECT_THAT(other_msg.GetReflection()->MutableMap(&other_msg, non_map_field),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("requires a map field")));
+
+  // Mismatched field from another descriptor
+  EXPECT_THAT(reflection->GetMap(message, non_map_field),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Field does not match message type")));
+  EXPECT_THAT(reflection->MutableMap(&message, non_map_field),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Field does not match message type")));
+
+  // Mismatched message reflection
+  EXPECT_THAT(reflection->GetMap(other_msg, map_i32_field),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("not the right object for reflection")));
+
+  ASSERT_TRUE(reflection->GetMap(message, map_i32_field).ok());
+  ASSERT_TRUE(reflection->MutableMap(&message, map_i32_field).ok());
+
+  auto map = reflection->MutableMap(&message, map_i32_field).value();
+
+  // 2. MapKey type mismatch or uninitialized key
+  MapKey uninit_key;
+  MapKey int64_key;
+  int64_key.SetInt64Value(42);
+  MapKey int32_key;
+  int32_key.SetInt32Value(42);
+
+  EXPECT_FALSE(map.contains(uninit_key));
+  EXPECT_FALSE(map.contains(int64_key));
+  EXPECT_EQ(map.find(uninit_key), map.end());
+  EXPECT_EQ(map.find(int64_key), map.end());
+
+  EXPECT_FALSE(map.erase(uninit_key));
+  EXPECT_FALSE(map.erase(int64_key));
+
+  EXPECT_THAT(
+      map.try_emplace(uninit_key),
+      StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("uninitialized")));
+  EXPECT_THAT(
+      map.try_emplace(int64_key),
+      StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("type mismatch")));
+
+  // Valid try_emplace
+  auto res = map.try_emplace(int32_key);
+  ASSERT_TRUE(res.ok());
+  EXPECT_TRUE(res->inserted);
+  EXPECT_EQ(res->iter->key().GetInt32Value(), 42);
+
+  // 3. assign and swap between incompatible map handles
+  auto map_i64 = reflection->MutableMap(&message, map_i64_field).value();
+  EXPECT_THAT(map.assign(map_i64),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map key or value CppType mismatch")));
+  EXPECT_THAT(map.swap(map_i64),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map key or value CppType mismatch")));
+
+  // Same key/value CppType (int32 -> message), different message prototypes
+  // (when empty, when one is non-empty, and via GetMap)
+  auto map_foreign =
+      reflection
+          ->MutableMap(&message,
+                       desc->FindFieldByName("map_int32_foreign_message"))
+          .value();
+  const auto* all_types_field = desc->FindFieldByName("map_int32_all_types");
+  auto map_all_types =
+      reflection->MutableMap(&message, all_types_field).value();
+  auto const_map_all_types_empty =
+      reflection->GetMap(message, all_types_field).value();
+  EXPECT_THAT(map_foreign.assign(map_all_types),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map value message prototype mismatch")));
+  EXPECT_THAT(map_foreign.assign(const_map_all_types_empty),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map value message prototype mismatch")));
+  EXPECT_THAT(map_foreign.swap(map_all_types),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map value message prototype mismatch")));
+
+  ASSERT_TRUE(map_all_types.try_emplace(int32_key).ok());
+  auto const_map_all_types_nonempty =
+      reflection->GetMap(message, all_types_field).value();
+  EXPECT_THAT(map_foreign.assign(map_all_types),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map value message prototype mismatch")));
+  EXPECT_THAT(map_foreign.assign(const_map_all_types_nonempty),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map value message prototype mismatch")));
+  EXPECT_THAT(map_foreign.swap(map_all_types),
+              StatusIs(absl::StatusCode::kInvalidArgument,
+                       HasSubstr("Map value message prototype mismatch")));
+}
+
+TEST_F(MapImplTest, GenericMapRefIteratorAndContainerTraits) {
+  using MutIterTraits = std::iterator_traits<GenericMapRef::iterator>;
+  static_assert(std::is_same_v<MutIterTraits::iterator_category,
+                               std::input_iterator_tag>);
+  static_assert(std::is_same_v<GenericMapRef::iterator::iterator_concept,
+                               std::forward_iterator_tag>);
+  static_assert(std::is_same_v<MutIterTraits::value_type, MapIteratorEntry>);
+  static_assert(std::is_same_v<MutIterTraits::difference_type, ptrdiff_t>);
+  static_assert(
+      std::is_same_v<MutIterTraits::pointer, const MapIteratorEntry*>);
+  static_assert(std::is_same_v<MutIterTraits::reference, MapIteratorEntry>);
+
+  using ConstIterTraits = std::iterator_traits<GenericConstMapRef::iterator>;
+  static_assert(std::is_same_v<ConstIterTraits::iterator_category,
+                               std::input_iterator_tag>);
+  static_assert(std::is_same_v<GenericConstMapRef::iterator::iterator_concept,
+                               std::forward_iterator_tag>);
+  static_assert(
+      std::is_same_v<ConstIterTraits::value_type, MapConstIteratorEntry>);
+  static_assert(std::is_same_v<ConstIterTraits::difference_type, ptrdiff_t>);
+  static_assert(
+      std::is_same_v<ConstIterTraits::pointer, const MapConstIteratorEntry*>);
+  static_assert(
+      std::is_same_v<ConstIterTraits::reference, MapConstIteratorEntry>);
+
+  static_assert(std::is_same_v<GenericMapRef::const_iterator,
+                               GenericConstMapRef::iterator>);
+  static_assert(std::is_same_v<GenericConstMapRef::const_iterator,
+                               GenericConstMapRef::iterator>);
+
+
+  TestMap message;
+  const auto* desc = message.descriptor();
+  const auto* reflection = message.GetReflection();
+  const auto* map_i32_field = desc->FindFieldByName("map_int32_int32");
+
+  GenericMapRef map = reflection->MutableMap(&message, map_i32_field).value();
+  GenericConstMapRef const_map =
+      reflection->GetMap(message, map_i32_field).value();
+
+  EXPECT_EQ(GenericMapRef::iterator{}, GenericMapRef::iterator{});
+  EXPECT_EQ(GenericConstMapRef::iterator{}, GenericConstMapRef::iterator{});
+  EXPECT_EQ(std::distance(map.begin(), map.end()), 0);
+  EXPECT_EQ(std::distance(const_map.begin(), const_map.end()), 0);
+  EXPECT_THAT(map, IsEmpty());
+  EXPECT_THAT(const_map, IsEmpty());
+  EXPECT_THAT(map, ::testing::BeginEndDistanceIs(0));
+  EXPECT_THAT(const_map, ::testing::BeginEndDistanceIs(0));
+
+  MapKey key;
+  key.SetInt32Value(7);
+  auto res = map.try_emplace(key);
+  ASSERT_TRUE(res.ok());
+  res->iter->value().SetInt32Value(99);
+
+  EXPECT_EQ(std::distance(map.begin(), map.end()), 1);
+  EXPECT_EQ(std::distance(const_map.begin(), const_map.end()), 1);
+  EXPECT_THAT(map, ::testing::SizeIs(1));
+  EXPECT_THAT(const_map, ::testing::SizeIs(1));
+  EXPECT_THAT(map, ::testing::BeginEndDistanceIs(1));
+  EXPECT_THAT(const_map, ::testing::BeginEndDistanceIs(1));
+  EXPECT_THAT(map, ::testing::UnorderedElementsAre(::testing::Property(
+                       &GenericMapRef::value_type::key, key)));
+  EXPECT_THAT(const_map, ::testing::UnorderedElementsAre(::testing::Property(
+                             &GenericConstMapRef::value_type::key, key)));
+}
+
 }  // namespace
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 47f67b3..44b255f 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -107,6 +107,8 @@
 #include "absl/base/optimization.h"
 #include "absl/log/absl_check.h"
 #include "absl/memory/memory.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/optional.h"
@@ -137,13 +139,14 @@
 
 // Defined in other files.
 class AssignDescriptorsHelper;
-class ConstMapIterator;
+class ABSL_ATTRIBUTE_VIEW ConstMapIterator;
 class DynamicMessageFactory;
 class GeneratedMessageReflectionTestHelper;
-class MapKey;
-class MapValueConstRef;
-class MapValueRef;
-class MapIterator;
+class ABSL_ATTRIBUTE_VIEW MapKey;
+class ABSL_ATTRIBUTE_VIEW MapValueConstRef;
+class ABSL_ATTRIBUTE_VIEW MapValueRef;
+class ABSL_ATTRIBUTE_VIEW GenericMapRef;
+class ABSL_ATTRIBUTE_VIEW GenericConstMapRef;
 class MapReflectionTester;
 class TextFormat;
 
@@ -213,7 +216,6 @@
 class ReflectionOps;           // reflection_ops.h
 class MapKeySorter;            // wire_format.cc
 class WireFormat;              // wire_format.h
-class MapFieldReflectionTest;  // map_test.cc
 }  // namespace internal
 
 template <typename T>
@@ -972,6 +974,77 @@
   MutableRepeatedFieldRef<T> GetMutableRepeatedFieldRef(
       Message* message, const FieldDescriptor* field) const;
 
+  // Get a map field as a generic read-only handle.
+  // The generic key and value types give the relevant type information needed
+  // ot access them.
+  //
+  // Class synopsis:
+  //
+  // class GenericConstMapRef {
+  //  public:
+  //   using iterator = ...;
+  //   using const_iterator = ...;
+  //   using value_type = ...;
+  //   using key_type = MapKey;
+  //   using mapped_type = MapValueConstRef;
+  //
+  //   iterator begin() const;
+  //   iterator end() const;
+  //   size_t size() const;
+  //   bool empty() const;
+  //   bool contains(const MapKey& key) const;
+  //   iterator find(const MapKey& key) const;
+  // };
+  //
+  // The `value_type` differs from standard map types in that the key and value
+  // are accessed as `elem.key()` and `elem.value()` instead of `elem.first` and
+  // `elem.second`. The accessors return `MapKey` and `MapValueConstRef`.
+  //
+  // Example usage:
+  //
+  // ASSIGN_OR_RETURN(auto map, reflection->GetMap(message, field));
+  // for (auto entry : map) {
+  //   MapKey key = entry.key();
+  //   MapValueConstRef value = entry.value();
+  //   ...
+  // }
+  absl::StatusOr<GenericConstMapRef> GetMap(const Message& message
+                                                ABSL_ATTRIBUTE_LIFETIME_BOUND,
+                                            const FieldDescriptor* field) const;
+
+  // Get a map field as a generic mutable handle.
+  // `GenericMapRef` is similar to `GenericConstMapRef` but adds the following
+  // mutating operations:
+  //
+  //    void clear() const;
+  //    size_t erase(const MapKey& key) const;
+  //    absl::StatusOr<InsertResult> try_emplace(const MapKey& key) const;
+  //
+  //    // Deep container operations
+  //    absl::Status assign(const GenericMapRef& other) const;
+  //    absl::Status swap(const GenericMapRef& other) const;
+  //
+  // `try_emplace` behaves like a standard one, except that does not allow
+  // passing an initial value. The `mapped_type` will always be default
+  // initialized if the operation results in an insertion.
+  //
+  // In addition, the `value()` you get from the iterator returns a
+  // `MapValueRef`, which allows for mutable access to the value.
+  //
+  // Example usage:
+  //
+  // // Increase value for the key
+  // MapKey key = ...;
+  // ASSIGN_OR_RETURN(auto map, reflection->MutableMap(message, field));
+  // auto it = map.find(key);
+  // if (it != map.end()) {
+  //   it->value()->SetInt64Value(it->value()->GetInt64Value() + 1);
+  // }
+  //
+  absl::StatusOr<GenericMapRef> MutableMap(Message* message
+                                               ABSL_ATTRIBUTE_LIFETIME_BOUND,
+                                           const FieldDescriptor* field) const;
+
   // DEPRECATED. Please use Get(Mutable)RepeatedFieldRef() for repeated field
   // access. The following repeated field accessors will be removed in the
   // future.
@@ -1237,7 +1310,6 @@
   friend class util::MessageDifferencer;
 #define GOOGLE_PROTOBUF_HAS_CEL_MAP_REFLECTION_FRIEND
   friend class expr::CelMapReflectionFriend;
-  friend class internal::MapFieldReflectionTest;
   friend class internal::MapKeySorter;
   friend class internal::MessageUtil;
   friend class internal::WireFormat;
@@ -1266,60 +1338,35 @@
 
   friend class MapReflectionTester;
 
-  // Returns true if key is in map. Returns false if key is not in map field.
+  // TODO: We keep these legacy functions temporarily.
+  // We have friend projects that are using the internal API.
+  // Once they are updated to use the public API we can clean this up.
+  [[deprecated("Legacy internal function. Use GetMap instead.")]]
   bool ContainsMapKey(const Message& message, const FieldDescriptor* field,
                       const MapKey& key) const;
-
-  // If key is in map field: Saves the value pointer to val and returns
-  // false. If key in not in map field: Insert the key into map, saves
-  // value pointer to val and returns true. Users are able to modify the
-  // map value by MapValueRef.
+  [[deprecated("Legacy internal function. Use MutableMap instead.")]]
   bool InsertOrLookupMapValue(Message* message, const FieldDescriptor* field,
                               const MapKey& key, MapValueRef* val) const;
-
-  // If key is in map field: Saves the value pointer to val and returns true.
-  // Returns false if key is not in map field. Users are NOT able to modify
-  // the value by MapValueConstRef.
+  [[deprecated("Legacy internal function. Use GetMap instead.")]]
   bool LookupMapValue(const Message& message, const FieldDescriptor* field,
                       const MapKey& key, MapValueConstRef* val) const;
-  bool LookupMapValue(const Message&, const FieldDescriptor*, const MapKey&,
-                      MapValueRef*) const = delete;
-
-  // Delete and returns true if key is in the map field. Returns false
-  // otherwise.
+  [[deprecated("Legacy internal function. Use MutableMap instead.")]]
   bool DeleteMapValue(Message* message, const FieldDescriptor* field,
                       const MapKey& key) const;
-
-  // Returns a MapIterator referring to the first element in the map field.
-  // If the map field is empty, this function returns the same as
-  // reflection::MapEnd. Mutation to the field may invalidate the iterator.
-  MapIterator MapBegin(Message* message, const FieldDescriptor* field) const;
-
-  // Returns a MapIterator referring to the theoretical element that would
-  // follow the last element in the map field. It does not point to any
-  // real element. Mutation to the field may invalidate the iterator.
-  MapIterator MapEnd(Message* message, const FieldDescriptor* field) const;
-
-  // Returns a ConstMapIterator referring to the first element in the map field.
-  // If the map field is empty, this function returns the same as
-  // reflection::ConstMapEnd. Mutation to the field may invalidate the iterator.
+  PROTOBUF_IGNORE_DEPRECATION_START
+  [[deprecated("Legacy internal function. Use GetMap instead.")]]
   ConstMapIterator ConstMapBegin(const Message* message,
                                  const FieldDescriptor* field) const;
-
-  // Returns a ConstMapIterator referring to the theoretical element that would
-  // follow the last element in the map field. It does not point to any
-  // real element. Mutation to the field may invalidate the iterator.
+  [[deprecated("Legacy internal function. Use GetMap instead.")]]
   ConstMapIterator ConstMapEnd(const Message* message,
                                const FieldDescriptor* field) const;
-
-  // Get the number of <key, value> pair of a map field. The result may be
-  // different from FieldSize which can have duplicate keys.
+  PROTOBUF_IGNORE_DEPRECATION_STOP
+  [[deprecated("Legacy internal function. Use GetMap instead.")]]
   int MapSize(const Message& message, const FieldDescriptor* field) const;
 
-  // Help method for MapIterator.
-  template <bool>
-  friend class MapIteratorBase;
   friend class WireFormatForMapFieldTest;
+  const internal::ClassData* GetClassDataForMapMessageValueType(
+      const FieldDescriptor* field, const internal::UntypedMapBase& map) const;
   internal::MapFieldBase* MutableMapData(Message* message,
                                          const FieldDescriptor* field) const;
 
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index ba44721..cdd1a71 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -201,12 +201,10 @@
               const MapFieldBase* map_field =
                   reflection->GetMapData(message, field);
               if (map_field->IsMapValid()) {
-                ConstMapIterator it(&message, field);
-                ConstMapIterator end_map(&message, field);
-                for (map_field->ConstMapBegin(&it),
-                     map_field->ConstMapEnd(&end_map);
-                     it != end_map; ++it) {
-                  if (!it.GetValueRef().GetMessageValue().IsInitialized()) {
+                auto map = reflection->GetMap(message, field);
+                ABSL_DCHECK(map.ok());
+                for (auto entry : *map) {
+                  if (!entry.value().GetMessageValue().IsInitialized()) {
                     return false;
                   }
                 }
@@ -283,11 +281,10 @@
           const MapFieldBase* map_field =
               reflection->GetMapData(message, field);
           if (map_field->IsMapValid()) {
-            ConstMapIterator iter(&message, field);
-            ConstMapIterator end(&message, field);
-            for (map_field->ConstMapBegin(&iter), map_field->ConstMapEnd(&end);
-                 iter != end; ++iter) {
-              if (!iter.GetValueRef().GetMessageValue().IsInitialized()) {
+            auto map = reflection->GetMap(message, field);
+            ABSL_DCHECK(map.ok());
+            for (auto entry : *map) {
+              if (!entry.value().GetMessageValue().IsInitialized()) {
                 return false;
               }
             }
@@ -344,11 +341,10 @@
         field->is_map() ? reflection->MutableMapData(message, field) : nullptr;
     if (map_field != nullptr && map_field->IsMapValid()) {
       if (IsMapValueMessageTyped(field)) {
-        MapIterator iter(message, field);
-        MapIterator end(message, field);
-        for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end;
-             ++iter) {
-          iter.MutableValueRef()->MutableMessageValue()->DiscardUnknownFields();
+        auto map = reflection->MutableMap(message, field);
+        ABSL_DCHECK(map.ok());
+        for (auto entry : *map) {
+          entry.value().MutableMessageValue()->DiscardUnknownFields();
         }
       }
       // Discard every unknown field inside messages in a repeated field.
diff --git a/src/google/protobuf/reflection_tester.cc b/src/google/protobuf/reflection_tester.cc
index 8934cf5..54a3392 100644
--- a/src/google/protobuf/reflection_tester.cc
+++ b/src/google/protobuf/reflection_tester.cc
@@ -10,10 +10,14 @@
 #include <cstddef>
 #include <cstdint>
 #include <string>
+#include <variant>
 #include <vector>
 
 #include <gtest/gtest.h>
 #include "absl/container/flat_hash_map.h"
+#include "absl/functional/overload.h"
+#include "absl/log/absl_log.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/descriptor.h"
 #include "google/protobuf/map_field.h"
@@ -400,226 +404,432 @@
                                                  foreign_c_, 1);
 }
 
+namespace {
+
+constexpr absl::string_view kMapFields[] = {
+    "map_int32_int32",
+    "map_int64_int64",
+    "map_uint32_uint32",
+    "map_uint64_uint64",
+    "map_sint32_sint32",
+    "map_sint64_sint64",
+    "map_fixed32_fixed32",
+    "map_fixed64_fixed64",
+    "map_sfixed32_sfixed32",
+    "map_sfixed64_sfixed64",
+    "map_int32_float",
+    "map_int32_double",
+    "map_bool_bool",
+    "map_string_string",
+    "map_int32_bytes",
+    "map_int32_enum",
+    "map_int32_foreign_message",
+};
+
+struct EnumVal {
+  int value = 0;
+  friend bool operator==(EnumVal a, EnumVal b) { return a.value == b.value; }
+};
+
+using KeyVariant =
+    std::variant<int32_t, int64_t, uint32_t, uint64_t, bool, std::string>;
+using ValueVariant = std::variant<int32_t, int64_t, uint32_t, uint64_t, float,
+                                  double, bool, std::string, EnumVal>;
+
+inline KeyVariant GetKeyVariant(const MapKey& key) {
+  switch (key.type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return key.GetInt32Value();
+    case FieldDescriptor::CPPTYPE_INT64:
+      return key.GetInt64Value();
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return key.GetUInt32Value();
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return key.GetUInt64Value();
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return key.GetBoolValue();
+    case FieldDescriptor::CPPTYPE_STRING:
+      return std::string(key.GetStringValue());
+    default:
+      ABSL_LOG(FATAL) << "Unsupported key type: " << key.type();
+  }
+}
+
+template <typename T>
+inline ValueVariant GetValueVariant(const T& ref) {
+  switch (ref.type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return ref.GetInt32Value();
+    case FieldDescriptor::CPPTYPE_INT64:
+      return ref.GetInt64Value();
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return ref.GetUInt32Value();
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return ref.GetUInt64Value();
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return ref.GetFloatValue();
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return ref.GetDoubleValue();
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return ref.GetBoolValue();
+    case FieldDescriptor::CPPTYPE_STRING:
+      return std::string(ref.GetStringValue());
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return EnumVal{ref.GetEnumValue()};
+    default:
+      ABSL_LOG(FATAL) << "Unsupported value type: " << ref.type();
+  }
+}
+
+inline void SetMapKey(MapKey& key, const KeyVariant& val) {
+  std::visit(absl::Overload{
+                 [&](int32_t v) { key.SetInt32Value(v); },
+                 [&](int64_t v) { key.SetInt64Value(v); },
+                 [&](uint32_t v) { key.SetUInt32Value(v); },
+                 [&](uint64_t v) { key.SetUInt64Value(v); },
+                 [&](bool v) { key.SetBoolValue(v); },
+                 [&](const std::string& v) { key.SetStringValue(v); },
+             },
+             val);
+}
+
+inline MapKey MakeMapKey(const KeyVariant& val) {
+  MapKey key;
+  SetMapKey(key, val);
+  return key;
+}
+
+inline void SetMapValue(MapValueRef ref, const ValueVariant& val) {
+  std::visit(absl::Overload{
+                 [&](int32_t v) { ref.SetInt32Value(v); },
+                 [&](int64_t v) { ref.SetInt64Value(v); },
+                 [&](uint32_t v) { ref.SetUInt32Value(v); },
+                 [&](uint64_t v) { ref.SetUInt64Value(v); },
+                 [&](float v) { ref.SetFloatValue(v); },
+                 [&](double v) { ref.SetDoubleValue(v); },
+                 [&](bool v) { ref.SetBoolValue(v); },
+                 [&](const std::string& v) { ref.SetStringValue(v); },
+                 [&](EnumVal v) { ref.SetEnumValue(v.value); },
+             },
+             val);
+}
+
+void SetMapFieldHelper(absl::StatusOr<GenericMapRef> map_ref,
+                       const KeyVariant& k0_val, const ValueVariant& val0,
+                       const KeyVariant& k1_val, const ValueVariant& val1) {
+  GenericMapRef map = map_ref.value();
+  MapKey key0 = MakeMapKey(k0_val);
+  MapKey key1 = MakeMapKey(k1_val);
+
+  GenericConstMapRef cmap = map;
+
+  EXPECT_TRUE(map.empty());
+  EXPECT_TRUE(cmap.empty());
+  EXPECT_EQ(map.size(), 0);
+  EXPECT_EQ(cmap.size(), 0);
+  EXPECT_FALSE(map.contains(key0));
+  EXPECT_FALSE(cmap.contains(key0));
+  EXPECT_EQ(map.find(key0), map.end());
+  EXPECT_EQ(cmap.find(key0), cmap.end());
+
+  auto res0 = map.try_emplace(key0).value();
+  EXPECT_TRUE(res0.inserted);
+  EXPECT_NE(res0.iter, map.end());
+  EXPECT_EQ(res0.iter->key(), key0);
+  SetMapValue(res0.iter->value(), val0);
+
+  EXPECT_FALSE(map.empty());
+  EXPECT_FALSE(cmap.empty());
+  EXPECT_EQ(map.size(), 1);
+  EXPECT_EQ(cmap.size(), 1);
+  EXPECT_TRUE(map.contains(key0));
+  EXPECT_TRUE(cmap.contains(key0));
+  EXPECT_NE(map.find(key0), map.end());
+  EXPECT_NE(cmap.find(key0), cmap.end());
+  EXPECT_EQ(GetValueVariant(map.find(key0)->value()), val0);
+  EXPECT_EQ(GetValueVariant(cmap.find(key0)->value()), val0);
+
+  EXPECT_FALSE(map.contains(key1));
+  EXPECT_FALSE(cmap.contains(key1));
+
+  auto res1 = map.try_emplace(key1).value();
+  EXPECT_TRUE(res1.inserted);
+  EXPECT_EQ(map.size(), 2);
+  EXPECT_EQ(cmap.size(), 2);
+  EXPECT_TRUE(map.contains(key1));
+  EXPECT_TRUE(cmap.contains(key1));
+
+  // Set the value for key1.
+  SetMapValue(res1.iter->value(), val1);
+
+  // Duplicate insertion via try_emplace should return false and not overwrite.
+  auto dup = map.try_emplace(key1).value();
+  EXPECT_FALSE(dup.inserted);
+  EXPECT_EQ(GetValueVariant(dup.iter->value()), val1);
+
+  EXPECT_EQ(map.size(), 2);
+  EXPECT_EQ(cmap.size(), 2);
+  EXPECT_TRUE(map.contains(key0));
+  EXPECT_TRUE(cmap.contains(key0));
+  EXPECT_TRUE(map.contains(key1));
+  EXPECT_TRUE(cmap.contains(key1));
+  EXPECT_EQ(GetValueVariant(map.find(key1)->value()), val1);
+  EXPECT_EQ(GetValueVariant(cmap.find(key1)->value()), val1);
+
+  // Clear and populate standard map elements for downstream tests.
+  map.clear();
+  EXPECT_TRUE(map.empty());
+  EXPECT_TRUE(cmap.empty());
+
+  KeyVariant std_k0, std_k1;
+  std::visit(absl::Overload{
+                 [&](int32_t) {
+                   std_k0 = int32_t{0};
+                   std_k1 = int32_t{1};
+                 },
+                 [&](int64_t) {
+                   std_k0 = int64_t{0};
+                   std_k1 = int64_t{1};
+                 },
+                 [&](uint32_t) {
+                   std_k0 = uint32_t{0};
+                   std_k1 = uint32_t{1};
+                 },
+                 [&](uint64_t) {
+                   std_k0 = uint64_t{0};
+                   std_k1 = uint64_t{1};
+                 },
+                 [&](bool) {
+                   std_k0 = false;
+                   std_k1 = true;
+                 },
+                 [&](const std::string&) {
+                   std_k0 = MapReflectionTester::long_string();
+                   std_k1 = MapReflectionTester::long_string_2();
+                 },
+             },
+             k0_val);
+
+  ValueVariant std_v0, std_v1;
+  std::visit(absl::Overload{
+                 [&](int32_t) {
+                   std_v0 = int32_t{0};
+                   std_v1 = int32_t{1};
+                 },
+                 [&](int64_t) {
+                   std_v0 = int64_t{0};
+                   std_v1 = int64_t{1};
+                 },
+                 [&](uint32_t) {
+                   std_v0 = uint32_t{0};
+                   std_v1 = uint32_t{1};
+                 },
+                 [&](uint64_t) {
+                   std_v0 = uint64_t{0};
+                   std_v1 = uint64_t{1};
+                 },
+                 [&](float) {
+                   std_v0 = 0.0f;
+                   std_v1 = 1.0f;
+                 },
+                 [&](double) {
+                   std_v0 = 0.0;
+                   std_v1 = 1.0;
+                 },
+                 [&](bool) {
+                   std_v0 = false;
+                   std_v1 = true;
+                 },
+                 [&](const std::string&) {
+                   std_v0 = MapReflectionTester::long_string();
+                   std_v1 = MapReflectionTester::long_string_2();
+                 },
+                 [&](EnumVal) {
+                   std_v0 = val0;
+                   std_v1 = val1;
+                 },
+             },
+             val0);
+
+  SetMapValue(map.try_emplace(MakeMapKey(std_k0)).value().iter->value(),
+              std_v0);
+  SetMapValue(map.try_emplace(MakeMapKey(std_k1)).value().iter->value(),
+              std_v1);
+  EXPECT_EQ(map.size(), 2);
+  EXPECT_EQ(cmap.size(), 2);
+}
+
+void ModifyMapFieldHelper(absl::StatusOr<GenericMapRef> map_ref,
+                          const KeyVariant& k_val,
+                          const ValueVariant& new_val) {
+  GenericMapRef map = map_ref.value();
+  MapKey key = MakeMapKey(k_val);
+  EXPECT_EQ(map.size(), 2);
+  EXPECT_TRUE(map.contains(key));
+  auto dup = map.try_emplace(key).value();
+  EXPECT_FALSE(dup.inserted);
+  SetMapValue(map.find(key)->value(), new_val);
+  EXPECT_EQ(GetValueVariant(map.find(key)->value()), new_val);
+  EXPECT_EQ(map.size(), 2);
+}
+
+template <typename MapRef, typename StdMap>
+void ExpectMapIteratorHelper(MapRef map_ref, const StdMap& map) {
+  using KeyT = typename StdMap::key_type;
+  using ValT = typename StdMap::mapped_type;
+  EXPECT_EQ(map_ref.size(), map.size());
+  EXPECT_FALSE(map_ref.empty());
+
+  size_t count = 0;
+  for (auto entry : map_ref) {
+    auto key = std::get<KeyT>(GetKeyVariant(entry.key()));
+    auto val = std::get<ValT>(GetValueVariant(entry.value()));
+    auto it = map.find(key);
+    ASSERT_NE(it, map.end());
+    EXPECT_EQ(it->second, val);
+    ++count;
+  }
+  EXPECT_EQ(count, map.size());
+
+  // Iterator prefix/postfix ++ and arrow operator
+  auto it = map_ref.begin();
+  ASSERT_NE(it, map_ref.end());
+  EXPECT_EQ(GetValueVariant((*it).value()), GetValueVariant(it->value()));
+  EXPECT_EQ(GetKeyVariant((*it).key()), GetKeyVariant(it->key()));
+  auto it_copy = it++;
+  EXPECT_NE(it, it_copy);
+  EXPECT_EQ(it_copy, map_ref.begin());
+}
+
+}  // namespace
+
 void MapReflectionTester::SetMapFieldsViaMapReflection(Message* message) {
   const Reflection* reflection = message->GetReflection();
 
-  Message* sub_foreign_message = nullptr;
-  MapValueRef map_val;
-  MapValueConstRef map_val_const;
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_int32")),
+                    int32_t{10}, int32_t{11}, int32_t{20}, int32_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_int64_int64")),
+                    int64_t{10}, int64_t{11}, int64_t{20}, int64_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_uint32_uint32")),
+                    uint32_t{10}, uint32_t{11}, uint32_t{20}, uint32_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_uint64_uint64")),
+                    uint64_t{10}, uint64_t{11}, uint64_t{20}, uint64_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_sint32_sint32")),
+                    int32_t{10}, int32_t{11}, int32_t{20}, int32_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_sint64_sint64")),
+                    int64_t{10}, int64_t{11}, int64_t{20}, int64_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_fixed32_fixed32")),
+                    uint32_t{10}, uint32_t{11}, uint32_t{20}, uint32_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_fixed64_fixed64")),
+                    uint64_t{10}, uint64_t{11}, uint64_t{20}, uint64_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_sfixed32_sfixed32")),
+                    int32_t{10}, int32_t{11}, int32_t{20}, int32_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_sfixed64_sfixed64")),
+                    int64_t{10}, int64_t{11}, int64_t{20}, int64_t{21});
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_float")),
+                    int32_t{10}, 11.0f, int32_t{20}, 21.0f);
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_double")),
+                    int32_t{10}, 11.0, int32_t{20}, 21.0);
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_bool_bool")), false,
+                    true, true, false);
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_string_string")),
+                    std::string("key_a"), std::string("val_a"),
+                    std::string("key_b"), std::string("val_b"));
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_bytes")),
+                    int32_t{10}, std::string("bytes_a"), int32_t{20},
+                    std::string("bytes_b"));
+  SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_enum")),
+                    int32_t{10}, EnumVal{map_enum_bar_->number()}, int32_t{20},
+                    EnumVal{map_enum_baz_->number()});
 
-  // Add first element.
-  std::string map_key_string;
-  MapKey map_key;
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_int32"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                 map_key, &map_val));
-  map_val.SetInt32Value(0);
+  // 17. map_int32_foreign_message
+  {
+    auto map =
+        reflection->MutableMap(message, F("map_int32_foreign_message")).value();
+    EXPECT_TRUE(map.empty());
+    EXPECT_EQ(map.size(), 0);
 
-  map_key.SetInt64Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int64_int64"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                 map_key, &map_val));
-  map_val.SetInt64Value(0);
+    MapKey k0 = MakeMapKey(int32_t{10});
+    MapKey k1 = MakeMapKey(int32_t{20});
 
-  map_key.SetUInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_uint32_uint32"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint32_uint32"), map_key, &map_val));
-  map_val.SetUInt32Value(0);
+    EXPECT_FALSE(map.contains(k0));
+    EXPECT_EQ(map.find(k0), map.end());
 
-  map_key.SetUInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint64_uint64"), map_key, &map_val));
-  map_val.SetUInt64Value(0);
+    auto res0 = map.try_emplace(k0).value();
+    EXPECT_TRUE(res0.inserted);
+    EXPECT_NE(res0.iter, map.end());
+    EXPECT_EQ(res0.iter->key(), k0);
+    Message* sub0 = res0.iter->value().MutableMessageValue();
+    sub0->GetReflection()->SetInt32(sub0, foreign_c_, 11);
 
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sint32_sint32"), map_key, &map_val));
-  map_val.SetInt32Value(0);
+    EXPECT_FALSE(map.empty());
+    EXPECT_EQ(map.size(), 1);
+    EXPECT_TRUE(map.contains(k0));
+    const Message& read_sub0 = map.find(k0)->value().GetMessageValue();
+    EXPECT_EQ(read_sub0.GetReflection()->GetInt32(read_sub0, foreign_c_), 11);
 
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sint64_sint64"), map_key, &map_val));
-  map_val.SetInt64Value(0);
+    EXPECT_FALSE(map.contains(k1));
 
-  map_key.SetUInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_fixed32_fixed32"), map_key, &map_val));
-  map_val.SetUInt32Value(0);
+    auto res1 = map.try_emplace(k1).value();
+    EXPECT_TRUE(res1.inserted);
+    Message* sub1 = res1.iter->value().MutableMessageValue();
+    EXPECT_EQ(map.size(), 2);
+    EXPECT_TRUE(map.contains(k1));
+    EXPECT_EQ(sub1->GetReflection()->GetInt32(*sub1, foreign_c_), 0);
 
-  map_key.SetUInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_fixed64_fixed64"), map_key, &map_val));
-  map_val.SetUInt64Value(0);
+    // Set the value for k1.
+    sub1->GetReflection()->SetInt32(sub1, foreign_c_, 21);
 
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sfixed32_sfixed32"), map_key, &map_val));
-  map_val.SetInt32Value(0);
+    auto dup = map.try_emplace(k1).value();
+    EXPECT_FALSE(dup.inserted);
 
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sfixed64_sfixed64"), map_key, &map_val));
-  map_val.SetInt64Value(0);
+    EXPECT_EQ(map.size(), 2);
+    EXPECT_TRUE(map.contains(k0));
+    EXPECT_TRUE(map.contains(k1));
+    EXPECT_EQ(map.find(k1)->value().GetMessageValue().GetReflection()->GetInt32(
+                  map.find(k1)->value().GetMessageValue(), foreign_c_),
+              21);
 
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_float"),
-                                                 map_key, &map_val));
-  map_val.SetFloatValue(0.0);
+    GenericConstMapRef const_map = map;
+    EXPECT_EQ(const_map.size(), 2);
+    EXPECT_FALSE(const_map.empty());
+    EXPECT_TRUE(const_map.contains(k0));
+    EXPECT_TRUE(const_map.contains(k1));
+    const Message& c_sub0 = const_map.find(k0)->value().GetMessageValue();
+    EXPECT_EQ(c_sub0.GetReflection()->GetInt32(c_sub0, foreign_c_), 11);
+    const Message& c_sub1 = const_map.find(k1)->value().GetMessageValue();
+    EXPECT_EQ(c_sub1.GetReflection()->GetInt32(c_sub1, foreign_c_), 21);
 
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_double"),
-                                                 map_key, &map_val));
-  map_val.SetDoubleValue(0.0);
-
-  map_key.SetBoolValue(false);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_bool_bool"), map_key,
-                                          &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"),
-                                                 map_key, &map_val));
-  map_val.SetBoolValue(false);
-
-  map_key_string = long_string();
-  map_key.SetStringValue(map_key_string);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_string_string"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_string_string"), map_key, &map_val));
-  map_val.SetStringValue(long_string());
-
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_bytes"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"),
-                                                 map_key, &map_val));
-  map_val.SetStringValue(long_string());
-
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_enum"),
-                                          map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_enum"),
-                                                 map_key, &map_val));
-  map_val.SetEnumValue(map_enum_bar_->number());
-
-  map_key.SetInt32Value(0);
-  EXPECT_FALSE(reflection->LookupMapValue(
-      *message, F("map_int32_foreign_message"), map_key, &map_val_const));
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 0);
-
-  // Add second element
-  map_key.SetInt32Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                 map_key, &map_val));
-  map_val.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                  map_key, &map_val));
-
-  map_key.SetInt64Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                 map_key, &map_val));
-  map_val.SetInt64Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                  map_key, &map_val));
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint32_uint32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(1);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
-                                     &map_val);
-  map_val.SetInt32Value(1);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
-                                     &map_val);
-  map_val.SetInt64Value(1);
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(1);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
-                                     map_key, &map_val);
-  map_val.SetInt32Value(1);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
-                                     map_key, &map_val);
-  map_val.SetInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
-                                     &map_val);
-  map_val.SetFloatValue(1.0);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
-                                     &map_val);
-  map_val.SetDoubleValue(1.0);
-
-  map_key.SetBoolValue(true);
-  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
-                                     &map_val);
-  map_val.SetBoolValue(true);
-
-  map_key_string = long_string_2();
-  map_key.SetStringValue(map_key_string);
-  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
-                                     &map_val);
-  map_val.SetStringValue(long_string_2());
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
-                                     &map_val);
-  map_val.SetStringValue(long_string_2());
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
-                                     &map_val);
-  map_val.SetEnumValue(map_enum_baz_->number());
-
-  map_key.SetInt32Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 1);
-}
-
-void MapReflectionTester::GetMapValueViaMapReflection(
-    Message* message, absl::string_view field_name, const MapKey& map_key,
-    MapValueRef* map_val) {
-  const Reflection* reflection = message->GetReflection();
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
-                                                  map_key, map_val));
+    // Clear and set standard elements (k0=0 with c=0, k1=1 with c=1)
+    map.clear();
+    EXPECT_TRUE(map.empty());
+    MapKey final_k0 = MakeMapKey(int32_t{0});
+    MapKey final_k1 = MakeMapKey(int32_t{1});
+    Message* final_sub0 =
+        map.try_emplace(final_k0).value().iter->value().MutableMessageValue();
+    final_sub0->GetReflection()->SetInt32(final_sub0, foreign_c_, 0);
+    Message* final_sub1 =
+        map.try_emplace(final_k1).value().iter->value().MutableMessageValue();
+    final_sub1->GetReflection()->SetInt32(final_sub1, foreign_c_, 1);
+    EXPECT_EQ(map.size(), 2);
+  }
 }
 
 void MapReflectionTester::DeleteMapValueViaMapReflection(
-    Message* message, absl::string_view field_name, const MapKey& map_key) {
+    Message* message, absl::string_view field_name, MapKey map_key) {
   const Reflection* reflection = message->GetReflection();
-  reflection->DeleteMapValue(message, F(field_name), map_key);
+  auto map = reflection->MutableMap(message, F(field_name)).value();
+
+  // We want to use the key once more after the first erase, so let's make sure
+  // string keys outlive the erase.
+  std::string str;
+  if (map_key.type() == FieldDescriptor::CPPTYPE_STRING) {
+    str = std::string(map_key.GetStringValue());
+    map_key.SetStringValue(str);
+  }
+
+  EXPECT_TRUE(map.erase(map_key));
+  EXPECT_FALSE(map.erase(map_key));
 }
 
 Message* MapReflectionTester::GetMapEntryViaReflection(
@@ -628,34 +838,10 @@
   return reflection->MutableRepeatedMessage(message, F(field_name), index);
 }
 
-MapIterator MapReflectionTester::MapBegin(Message* message,
-                                          absl::string_view field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MapBegin(message, F(field_name));
-}
-
-MapIterator MapReflectionTester::MapEnd(Message* message,
-                                        absl::string_view field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MapEnd(message, F(field_name));
-}
-
-ConstMapIterator MapReflectionTester::ConstMapBegin(
-    const Message* message, absl::string_view field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->ConstMapBegin(message, F(field_name));
-}
-
-ConstMapIterator MapReflectionTester::ConstMapEnd(
-    const Message* message, absl::string_view field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->ConstMapEnd(message, F(field_name));
-}
-
 int MapReflectionTester::MapSize(const Message& message,
                                  absl::string_view field_name) {
-  const Reflection* reflection = message.GetReflection();
-  return reflection->MapSize(message, F(field_name));
+  return static_cast<int>(
+      message.GetReflection()->GetMap(message, F(field_name)).value().size());
 }
 
 void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) {
@@ -680,101 +866,72 @@
   reflection->ClearField(message, F("map_int32_foreign_message"));
 }
 
+void MapReflectionTester::ClearMapFieldsViaMapReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  for (absl::string_view name : kMapFields) {
+    auto map = reflection->MutableMap(message, F(name)).value();
+    map.clear();
+    EXPECT_TRUE(map.empty());
+    EXPECT_EQ(map.size(), 0);
+    EXPECT_EQ(map.begin(), map.end());
+  }
+}
+
 void MapReflectionTester::ModifyMapFieldsViaReflection(Message* message) {
   const Reflection* reflection = message->GetReflection();
-  MapValueRef map_val;
-  Message* sub_foreign_message;
 
-  // Modify the second element
-  std::string map_key_string;
-  MapKey map_key;
-  map_key.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                  map_key, &map_val));
-  map_val.SetInt32Value(2);
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_int32")),
+                       int32_t{1}, int32_t{2});
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int64_int64")),
+                       int64_t{1}, int64_t{2});
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_uint32_uint32")),
+                       uint32_t{1}, uint32_t{2});
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_uint64_uint64")),
+                       uint64_t{1}, uint64_t{2});
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_sint32_sint32")),
+                       int32_t{1}, int32_t{2});
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_sint64_sint64")),
+                       int64_t{1}, int64_t{2});
+  ModifyMapFieldHelper(
+      reflection->MutableMap(message, F("map_fixed32_fixed32")), uint32_t{1},
+      uint32_t{2});
+  ModifyMapFieldHelper(
+      reflection->MutableMap(message, F("map_fixed64_fixed64")), uint64_t{1},
+      uint64_t{2});
+  ModifyMapFieldHelper(
+      reflection->MutableMap(message, F("map_sfixed32_sfixed32")), int32_t{1},
+      int32_t{2});
+  ModifyMapFieldHelper(
+      reflection->MutableMap(message, F("map_sfixed64_sfixed64")), int64_t{1},
+      int64_t{2});
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_float")),
+                       int32_t{1}, 2.0f);
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_double")),
+                       int32_t{1}, 2.0);
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_bool_bool")),
+                       true, false);
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_string_string")),
+                       long_string_2(), std::string("2"));
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_bytes")),
+                       int32_t{1}, std::string("2"));
+  ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_enum")),
+                       int32_t{1}, EnumVal{map_enum_foo_->number()});
 
-  map_key.SetInt64Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                  map_key, &map_val));
-  map_val.SetInt64Value(2);
-
-  map_key.SetUInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint32_uint32"), map_key, &map_val));
-  map_val.SetUInt32Value(2);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
-                                     &map_val);
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
-                                     &map_val);
-  map_val.SetInt64Value(2);
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(2);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
-                                     map_key, &map_val);
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
-                                     map_key, &map_val);
-  map_val.SetInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
-                                     &map_val);
-  map_val.SetFloatValue(2.0);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
-                                     &map_val);
-  map_val.SetDoubleValue(2.0);
-
-  map_key.SetBoolValue(true);
-  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
-                                     &map_val);
-  map_val.SetBoolValue(false);
-
-  map_key_string = long_string_2();
-  map_key.SetStringValue(map_key_string);
-  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("2");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("2");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
-                                     &map_val);
-  map_val.SetEnumValue(map_enum_foo_->number());
-
-  map_key.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 2);
+  {
+    MapKey k_int32 = MakeMapKey(int32_t{1});
+    auto map =
+        reflection->MutableMap(message, F("map_int32_foreign_message")).value();
+    EXPECT_EQ(map.size(), 2);
+    EXPECT_TRUE(map.contains(k_int32));
+    auto dup = map.try_emplace(k_int32).value();
+    EXPECT_FALSE(dup.inserted);
+    Message* sub = dup.iter->value().MutableMessageValue();
+    sub->GetReflection()->SetInt32(sub, foreign_c_, 2);
+    EXPECT_EQ(sub->GetReflection()->GetInt32(
+                  dup.iter->value().GetMessageValue(), foreign_c_),
+              2);
+    EXPECT_EQ(map.size(), 2);
+  }
 }
 
 void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) {
@@ -817,6 +974,39 @@
   }
 }
 
+void MapReflectionTester::SwapMapsViaMapReflection(Message* message1,
+                                                   Message* message2) {
+  const Reflection* reflection1 = message1->GetReflection();
+  const Reflection* reflection2 = message2->GetReflection();
+  for (absl::string_view name : kMapFields) {
+    auto map1 = reflection1->MutableMap(message1, F(name)).value();
+    auto map2 = reflection2->MutableMap(message2, F(name)).value();
+    EXPECT_TRUE(map1.swap(map2).ok());
+  }
+}
+
+void MapReflectionTester::AssignMapsViaMapReflection(Message* dst,
+                                                     Message* src) {
+  const Reflection* dst_reflection = dst->GetReflection();
+  const Reflection* src_reflection = src->GetReflection();
+  for (absl::string_view name : kMapFields) {
+    auto dst_map = dst_reflection->MutableMap(dst, F(name)).value();
+    auto src_map = src_reflection->MutableMap(src, F(name)).value();
+    EXPECT_TRUE(dst_map.assign(src_map).ok());
+  }
+}
+
+void MapReflectionTester::EraseMapValuesViaMapReflectionIterator(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  for (absl::string_view name : kMapFields) {
+    auto map = reflection->MutableMap(message, F(name)).value();
+    while (!map.empty()) {
+      map.erase(map.begin()->key());
+    }
+  }
+}
+
 void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection(
     Message* message) {
   const Reflection* reflection = message->GetReflection();
@@ -877,13 +1067,436 @@
 
 void MapReflectionTester::ExpectMapFieldsSetViaReflection(
     const Message& message) {
-  std::string scratch;
   const Reflection* reflection = message.GetReflection();
   const Message* sub_message;
   MapKey map_key;
-  MapValueConstRef map_value_const_ref;
 
-  // -----------------------------------------------------------------
+  for (auto f : kMapFields) {
+    ASSERT_EQ(2, reflection->FieldSize(message, F(f))) << f;
+    ASSERT_EQ(2, reflection->GetMap(message, F(f)).value().size()) << f;
+  }
+
+  {
+    absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int32_int32")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_int32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_int32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int32_int32")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int64_t, int64_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int64_int64")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_int64_int64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_int64_int64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt64Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int64_int64")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt64Value(), i);
+        EXPECT_EQ(it->value().GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<uint32_t, uint32_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_uint32_uint32")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
+        uint32_t key = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_uint32_uint32_key_);
+        uint32_t val = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_uint32_uint32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetUInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_uint32_uint32")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetUInt32Value(), i);
+        EXPECT_EQ(it->value().GetUInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<uint64_t, uint64_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_uint64_uint64")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
+        uint64_t key = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_uint64_uint64_key_);
+        uint64_t val = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_uint64_uint64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetUInt64Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_uint64_uint64")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetUInt64Value(), i);
+        EXPECT_EQ(it->value().GetUInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_sint32_sint32")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sint32_sint32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sint32_sint32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_sint32_sint32")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int64_t, int64_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_sint64_sint64")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sint64_sint64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sint64_sint64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt64Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_sint64_sint64")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt64Value(), i);
+        EXPECT_EQ(it->value().GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<uint32_t, uint32_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_fixed32_fixed32")) {
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_fixed32_fixed32"), i);
+        uint32_t key = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_fixed32_fixed32_key_);
+        uint32_t val = sub_message->GetReflection()->GetUInt32(
+            *sub_message, map_fixed32_fixed32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetUInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_fixed32_fixed32")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetUInt32Value(), i);
+        EXPECT_EQ(it->value().GetUInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<uint64_t, uint64_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_fixed64_fixed64")) {
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_fixed64_fixed64"), i);
+        uint64_t key = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_fixed64_fixed64_key_);
+        uint64_t val = sub_message->GetReflection()->GetUInt64(
+            *sub_message, map_fixed64_fixed64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetUInt64Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_fixed64_fixed64")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetUInt64Value(), i);
+        EXPECT_EQ(it->value().GetUInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_sfixed32_sfixed32")) {
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_sfixed32_sfixed32"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sfixed32_sfixed32_key_);
+        int32_t val = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_sfixed32_sfixed32_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_sfixed32_sfixed32")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetInt32Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int64_t, int64_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_sfixed64_sfixed64")) {
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_sfixed64_sfixed64"), i);
+        int64_t key = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sfixed64_sfixed64_key_);
+        int64_t val = sub_message->GetReflection()->GetInt64(
+            *sub_message, map_sfixed64_sfixed64_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt64Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_sfixed64_sfixed64")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt64Value(), i);
+        EXPECT_EQ(it->value().GetInt64Value(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, float> map = {{0, 0.0f}, {1, 1.0f}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int32_float")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_float_key_);
+        float val = sub_message->GetReflection()->GetFloat(
+            *sub_message, map_int32_float_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int32_float")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetFloatValue(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, double> map = {{0, 0.0}, {1, 1.0}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int32_double")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_double_key_);
+        double val = sub_message->GetReflection()->GetDouble(
+            *sub_message, map_int32_double_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int32_double")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetDoubleValue(), map[i]);
+      }
+    }
+  }
+  {
+    std::array<bool, 2> map = {false, true};
+    std::vector<bool> keys = {false, true};
+    std::vector<bool> vals = {false, true};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_bool_bool")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
+        bool key = sub_message->GetReflection()->GetBool(*sub_message,
+                                                         map_bool_bool_key_);
+        bool val = sub_message->GetReflection()->GetBool(*sub_message,
+                                                         map_bool_bool_val_);
+        EXPECT_EQ(map[key ? 1 : 0], val);
+      } else {
+        map_key.SetBoolValue(keys[i]);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_bool_bool")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetBoolValue(), keys[i]);
+        EXPECT_EQ(it->value().GetBoolValue(), vals[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<std::string, std::string> map = {
+        {long_string(), long_string()}, {long_string_2(), long_string_2()}};
+    std::vector<std::string> keys = {long_string(), long_string_2()};
+    std::vector<std::string> vals = {long_string(), long_string_2()};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_string_string")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
+        std::string key = sub_message->GetReflection()->GetString(
+            *sub_message, map_string_string_key_);
+        std::string val = sub_message->GetReflection()->GetString(
+            *sub_message, map_string_string_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetStringValue(keys[i]);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_string_string")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetStringValue(), keys[i]);
+        EXPECT_EQ(it->value().GetStringValue(), vals[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, std::string> map = {{0, long_string()},
+                                                     {1, long_string_2()}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int32_bytes")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_bytes_key_);
+        std::string val = sub_message->GetReflection()->GetString(
+            *sub_message, map_int32_bytes_val_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int32_bytes")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetStringValue(), map[i]);
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, const EnumValueDescriptor*> map = {
+        {0, map_enum_bar_}, {1, map_enum_baz_}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int32_enum")) {
+        sub_message =
+            &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_enum_key_);
+        PROTOBUF_IGNORE_DEPRECATION_START
+        const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
+            *sub_message, map_int32_enum_val_);
+        PROTOBUF_IGNORE_DEPRECATION_STOP
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int32_enum")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        EXPECT_EQ(it->value().GetEnumValue(), map[i]->number());
+      }
+    }
+  }
+  {
+    absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}};
+    for (int i = 0; i < 2; i++) {
+      if (IsRepeatedFieldValid(message, "map_int32_foreign_message")) {
+        sub_message = &reflection->GetRepeatedMessage(
+            message, F("map_int32_foreign_message"), i);
+        int32_t key = sub_message->GetReflection()->GetInt32(
+            *sub_message, map_int32_foreign_message_key_);
+        const Message& foreign_message =
+            sub_message->GetReflection()->GetMessage(
+                *sub_message, map_int32_foreign_message_val_);
+        int32_t val = foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                                foreign_c_);
+        EXPECT_EQ(map[key], val);
+      } else {
+        map_key.SetInt32Value(i);
+        GenericConstMapRef map_ref =
+            reflection->GetMap(message, F("map_int32_foreign_message")).value();
+        ASSERT_TRUE(map_ref.contains(map_key));
+        auto it = map_ref.find(map_key);
+        EXPECT_EQ(it->key().GetInt32Value(), i);
+        const Message& foreign_message = it->value().GetMessageValue();
+        EXPECT_EQ(foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                            foreign_c_),
+                  map[i]);
+      }
+    }
+  }
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
+    Message* message) {
+  ExpectMapFieldsSetViaReflectionIterator(*message);
+
+  // Also test mutable iteration, operator[], and at() on Message*
+  const Reflection* reflection = message->GetReflection();
+  for (absl::string_view name : kMapFields) {
+    GenericMapRef mut_map = reflection->MutableMap(message, F(name)).value();
+    EXPECT_EQ(mut_map.size(), 2);
+    EXPECT_FALSE(mut_map.empty());
+
+    size_t count = 0;
+    for (auto entry : mut_map) {
+      EXPECT_NE(entry.key().type(), FieldDescriptor::CPPTYPE_MESSAGE);
+      ++count;
+    }
+    EXPECT_EQ(count, 2);
+
+    // Test conversion from MapIterator to MapConstIterator
+    GenericConstMapRef::iterator cit = mut_map.begin();
+    EXPECT_TRUE(cit == mut_map.begin());
+    EXPECT_FALSE(cit != mut_map.begin());
+    EXPECT_EQ(cit->key(), mut_map.begin()->key());
+  }
+}
+
+void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
+    const Message& message) {
+  std::string serialized;
+  const Reflection* reflection = message.GetReflection();
 
   ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
   ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
@@ -903,737 +1516,137 @@
   ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
   ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
 
+  // Const methods do not invalidate map.
+  (void)message.DebugString();
+  (void)message.ShortDebugString();
+  EXPECT_TRUE(message.SerializeToString(&serialized));
+  (void)message.SpaceUsedLong();
+  (void)message.ByteSizeLong();
+
   {
     absl::flat_hash_map<int32_t, int32_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_int32_int32"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_int32_key_);
-        int32_t val = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_int32_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_TRUE(
-            reflection->ContainsMapKey(message, F("map_int32_int32"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_int32"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_int32_int32")).value(), map);
   }
   {
     absl::flat_hash_map<int64_t, int64_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_int64_int64"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
-        int64_t key = sub_message->GetReflection()->GetInt64(
-            *sub_message, map_int64_int64_key_);
-        int64_t val = sub_message->GetReflection()->GetInt64(
-            *sub_message, map_int64_int64_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt64Value(i);
-        EXPECT_TRUE(
-            reflection->ContainsMapKey(message, F("map_int64_int64"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int64_int64"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_int64_int64")).value(), map);
   }
   {
     absl::flat_hash_map<uint32_t, uint32_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_uint32_uint32"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
-        uint32_t key = sub_message->GetReflection()->GetUInt32(
-            *sub_message, map_uint32_uint32_key_);
-        uint32_t val = sub_message->GetReflection()->GetUInt32(
-            *sub_message, map_uint32_uint32_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetUInt32Value(i);
-        EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint32_uint32"),
-                                               map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint32_uint32"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_uint32_uint32")).value(), map);
   }
   {
     absl::flat_hash_map<uint64_t, uint64_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_uint64_uint64"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
-        uint64_t key = sub_message->GetReflection()->GetUInt64(
-            *sub_message, map_uint64_uint64_key_);
-        uint64_t val = sub_message->GetReflection()->GetUInt64(
-            *sub_message, map_uint64_uint64_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetUInt64Value(i);
-        EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint64_uint64"),
-                                               map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint64_uint64"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_uint64_uint64")).value(), map);
   }
   {
     absl::flat_hash_map<int32_t, int32_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_sint32_sint32"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_sint32_sint32_key_);
-        int32_t val = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_sint32_sint32_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_sint32_sint32"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint32_sint32"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_sint32_sint32")).value(), map);
   }
   {
     absl::flat_hash_map<int64_t, int64_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_sint64_sint64"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
-        int64_t key = sub_message->GetReflection()->GetInt64(
-            *sub_message, map_sint64_sint64_key_);
-        int64_t val = sub_message->GetReflection()->GetInt64(
-            *sub_message, map_sint64_sint64_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt64Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_sint64_sint64"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint64_sint64"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_sint64_sint64")).value(), map);
   }
   {
     absl::flat_hash_map<uint32_t, uint32_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_fixed32_fixed32"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message = &reflection->GetRepeatedMessage(
-            message, F("map_fixed32_fixed32"), i);
-        uint32_t key = sub_message->GetReflection()->GetUInt32(
-            *sub_message, map_fixed32_fixed32_key_);
-        uint32_t val = sub_message->GetReflection()->GetUInt32(
-            *sub_message, map_fixed32_fixed32_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetUInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_fixed32_fixed32"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(
-            message, F("map_fixed32_fixed32"), map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_fixed32_fixed32")).value(), map);
   }
   {
     absl::flat_hash_map<uint64_t, uint64_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_fixed64_fixed64"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message = &reflection->GetRepeatedMessage(
-            message, F("map_fixed64_fixed64"), i);
-        uint64_t key = sub_message->GetReflection()->GetUInt64(
-            *sub_message, map_fixed64_fixed64_key_);
-        uint64_t val = sub_message->GetReflection()->GetUInt64(
-            *sub_message, map_fixed64_fixed64_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetUInt64Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_fixed64_fixed64"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(
-            message, F("map_fixed64_fixed64"), map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_fixed64_fixed64")).value(), map);
   }
   {
     absl::flat_hash_map<int32_t, int32_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(
-              message, F("map_sfixed32_sfixed32"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message = &reflection->GetRepeatedMessage(
-            message, F("map_sfixed32_sfixed32"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_sfixed32_sfixed32_key_);
-        int32_t val = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_sfixed32_sfixed32_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_sfixed32_sfixed32"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message,
-                                               F("map_sfixed32_sfixed32"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_sfixed32_sfixed32")).value(), map);
   }
   {
     absl::flat_hash_map<int64_t, int64_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(
-              message, F("map_sfixed64_sfixed64"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message = &reflection->GetRepeatedMessage(
-            message, F("map_sfixed64_sfixed64"), i);
-        int64_t key = sub_message->GetReflection()->GetInt64(
-            *sub_message, map_sfixed64_sfixed64_key_);
-        int64_t val = sub_message->GetReflection()->GetInt64(
-            *sub_message, map_sfixed64_sfixed64_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt64Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_sfixed64_sfixed64"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message,
-                                               F("map_sfixed64_sfixed64"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_sfixed64_sfixed64")).value(), map);
   }
   {
     absl::flat_hash_map<int32_t, float> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_int32_float"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_float_key_);
-        float val = sub_message->GetReflection()->GetFloat(
-            *sub_message, map_int32_float_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_int32_float"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_float"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetFloatValue(), map[i]);
-      }
-    }
+    map[0] = 0.0f;
+    map[1] = 1.0f;
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_int32_float")).value(), map);
   }
   {
     absl::flat_hash_map<int32_t, double> map;
     map[0] = 0.0;
     map[1] = 1.0;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_int32_double"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_double_key_);
-        double val = sub_message->GetReflection()->GetDouble(
-            *sub_message, map_int32_double_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_int32_double"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_double"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetDoubleValue(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_int32_double")).value(), map);
   }
   {
-    std::array<bool, 2> map;
-    map[0] = false;
-    map[1] = true;
-    std::vector<bool> keys = {false, true};
-    std::vector<bool> vals = {false, true};
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_bool_bool"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
-        bool key = sub_message->GetReflection()->GetBool(*sub_message,
-                                                         map_bool_bool_key_);
-        bool val = sub_message->GetReflection()->GetBool(*sub_message,
-                                                         map_bool_bool_val_);
-        EXPECT_EQ(map[key ? 1 : 0], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetBoolValue(keys[i]);
-        EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"),
-                                                   map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_bool_bool"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetBoolValue(), vals[i]);
-      }
-    }
+    absl::flat_hash_map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_bool_bool")).value(), map);
   }
   {
     absl::flat_hash_map<std::string, std::string> map;
     map[long_string()] = long_string();
     map[long_string_2()] = long_string_2();
-    std::vector<std::string> keys = {long_string(), long_string_2()};
-    std::vector<std::string> vals = {long_string(), long_string_2()};
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_string_string"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
-        std::string key = sub_message->GetReflection()->GetString(
-            *sub_message, map_string_string_key_);
-        std::string val = sub_message->GetReflection()->GetString(
-            *sub_message, map_string_string_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetStringValue(keys[i]);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_string_string"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_string_string"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetStringValue(), vals[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_string_string")).value(), map);
   }
   {
     absl::flat_hash_map<int32_t, std::string> map;
     map[0] = long_string();
     map[1] = long_string_2();
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_int32_bytes"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_bytes_key_);
-        std::string val = sub_message->GetReflection()->GetString(
-            *sub_message, map_int32_bytes_val_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_int32_bytes"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_bytes"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetStringValue(), map[i]);
-      }
-    }
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_int32_bytes")).value(), map);
   }
   {
-    absl::flat_hash_map<int32_t, const EnumValueDescriptor*> map;
-    map[0] = map_enum_bar_;
-    map[1] = map_enum_baz_;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(message,
-                                                     F("map_int32_enum"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message =
-            &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_enum_key_);
-        PROTOBUF_IGNORE_DEPRECATION_START
-        const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
-            *sub_message, map_int32_enum_val_);
-        PROTOBUF_IGNORE_DEPRECATION_STOP
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"),
-                                                   map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_enum"),
-                                               map_key, &map_value_const_ref));
-        EXPECT_EQ(map_value_const_ref.GetEnumValue(), map[i]->number());
-      }
-    }
+    absl::flat_hash_map<int32_t, EnumVal> map;
+    map[0] = EnumVal{map_enum_bar_->number()};
+    map[1] = EnumVal{map_enum_baz_->number()};
+    ExpectMapIteratorHelper(
+        reflection->GetMap(message, F("map_int32_enum")).value(), map);
   }
   {
     absl::flat_hash_map<int32_t, int32_t> map;
     map[0] = 0;
     map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      const internal::MapFieldBase& map_field =
-          reflection->GetRaw<internal::MapFieldBase>(
-              message, F("map_int32_foreign_message"));
-      if (map_field.IsRepeatedFieldValid()) {
-        // Check with RepeatedField Reflection
-        sub_message = &reflection->GetRepeatedMessage(
-            message, F("map_int32_foreign_message"), i);
-        int32_t key = sub_message->GetReflection()->GetInt32(
-            *sub_message, map_int32_foreign_message_key_);
-        const Message& foreign_message =
-            sub_message->GetReflection()->GetMessage(
-                *sub_message, map_int32_foreign_message_val_);
-        int32_t val = foreign_message.GetReflection()->GetInt32(foreign_message,
-                                                                foreign_c_);
-        EXPECT_EQ(map[key], val);
-      } else {
-        // Check with Map Reflection
-        map_key.SetInt32Value(i);
-        EXPECT_EQ(true, reflection->ContainsMapKey(
-                            message, F("map_int32_foreign_message"), map_key));
-        EXPECT_TRUE(reflection->LookupMapValue(message,
-                                               F("map_int32_foreign_message"),
-                                               map_key, &map_value_const_ref));
-        const Message& foreign_message = map_value_const_ref.GetMessageValue();
-        EXPECT_EQ(foreign_message.GetReflection()->GetInt32(foreign_message,
-                                                            foreign_c_),
-                  map[i]);
-      }
-    }
-  }
-}
-
-void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
-    Message* message) {
-  std::string scratch;
-  std::string serialized;
-  const Reflection* reflection = message->GetReflection();
-
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message")));
-
-  {
-    absl::flat_hash_map<int32_t, int32_t> map;
-    map[0] = 0;
-    map[1] = 1;
+    GenericConstMapRef map_ref =
+        reflection->GetMap(message, F("map_int32_foreign_message")).value();
+    EXPECT_EQ(map_ref.size(), 2);
     int size = 0;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int32_int32"));
-         iter != reflection->ConstMapEnd(message, F("map_int32_int32"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      (void)message->DebugString();
-      (void)message->ShortDebugString();
-      EXPECT_TRUE(message->SerializeToString(&serialized));
-      (void)message->SpaceUsedLong();
-      (void)message->ByteSizeLong();
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-    EXPECT_EQ(size, 2);
-  }
-  {
-    absl::flat_hash_map<int64_t, int64_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int64_int64"));
-         iter != reflection->ConstMapEnd(message, F("map_int64_int64"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
-                iter.GetValueRef().GetInt64Value());
-    }
-  }
-  {
-    absl::flat_hash_map<uint32_t, uint32_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_uint32_uint32"));
-         iter != reflection->ConstMapEnd(message, F("map_uint32_uint32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
-                iter.GetValueRef().GetUInt32Value());
-    }
-  }
-  {
-    absl::flat_hash_map<uint64_t, uint64_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_uint64_uint64"));
-         iter != reflection->ConstMapEnd(message, F("map_uint64_uint64"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
-                iter.GetValueRef().GetUInt64Value());
-    }
-  }
-  {
-    absl::flat_hash_map<int32_t, int32_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_sint32_sint32"));
-         iter != reflection->ConstMapEnd(message, F("map_sint32_sint32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-  }
-  {
-    absl::flat_hash_map<int64_t, int64_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_sint64_sint64"));
-         iter != reflection->ConstMapEnd(message, F("map_sint64_sint64"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
-                iter.GetValueRef().GetInt64Value());
-    }
-  }
-  {
-    absl::flat_hash_map<uint32_t, uint32_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_fixed32_fixed32"));
-         iter != reflection->ConstMapEnd(message, F("map_fixed32_fixed32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
-                iter.GetValueRef().GetUInt32Value());
-    }
-  }
-  {
-    absl::flat_hash_map<uint64_t, uint64_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_fixed64_fixed64"));
-         iter != reflection->ConstMapEnd(message, F("map_fixed64_fixed64"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
-                iter.GetValueRef().GetUInt64Value());
-    }
-  }
-  {
-    absl::flat_hash_map<int32_t, int32_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_sfixed32_sfixed32"));
-         iter != reflection->ConstMapEnd(message, F("map_sfixed32_sfixed32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-  }
-  {
-    absl::flat_hash_map<int32_t, float> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int32_float"));
-         iter != reflection->ConstMapEnd(message, F("map_int32_float"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetFloatValue());
-    }
-  }
-  {
-    absl::flat_hash_map<int32_t, double> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int32_double"));
-         iter != reflection->ConstMapEnd(message, F("map_int32_double"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetDoubleValue());
-    }
-  }
-  {
-    std::array<bool, 2> map;
-    map[0] = false;
-    map[1] = true;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_bool_bool"));
-         iter != reflection->ConstMapEnd(message, F("map_bool_bool")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetBoolValue() ? 1 : 0],
-                iter.GetValueRef().GetBoolValue());
-    }
-  }
-  {
-    absl::flat_hash_map<std::string, std::string> map;
-    map[long_string()] = long_string();
-    map[long_string_2()] = long_string_2();
-    int size = 0;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_string_string"));
-         iter != reflection->ConstMapEnd(message, F("map_string_string"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      (void)message->DebugString();
-      (void)message->ShortDebugString();
-      EXPECT_TRUE(message->SerializeToString(&serialized));
-      (void)message->SpaceUsedLong();
-      (void)message->ByteSizeLong();
-      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
-                iter.GetValueRef().GetStringValue());
-    }
-    EXPECT_EQ(size, 2);
-  }
-  {
-    absl::flat_hash_map<int32_t, std::string> map;
-    map[0] = long_string();
-    map[1] = long_string_2();
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int32_bytes"));
-         iter != reflection->ConstMapEnd(message, F("map_int32_bytes"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetStringValue());
-    }
-  }
-  {
-    absl::flat_hash_map<int32_t, const EnumValueDescriptor*> map;
-    map[0] = map_enum_bar_;
-    map[1] = map_enum_baz_;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int32_enum"));
-         iter != reflection->ConstMapEnd(message, F("map_int32_enum"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(),
-                iter.GetValueRef().GetEnumValue());
-    }
-  }
-  {
-    absl::flat_hash_map<int32_t, int32_t> map;
-    map[0] = 0;
-    map[1] = 1;
-    int size = 0;
-    for (ConstMapIterator iter =
-             reflection->ConstMapBegin(message, F("map_int32_foreign_message"));
-         iter !=
-         reflection->ConstMapEnd(message, F("map_int32_foreign_message"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      (void)message->DebugString();
-      (void)message->ShortDebugString();
-      EXPECT_TRUE(message->SerializeToString(&serialized));
-      (void)message->SpaceUsedLong();
-      (void)message->ByteSizeLong();
-      const Message& sub_message = iter.GetValueRef().GetMessageValue();
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
+    for (auto iter = map_ref.begin(); iter != map_ref.end(); ++iter, ++size) {
+      const Message& sub = iter->value().GetMessageValue();
+      EXPECT_EQ(map[iter->key().GetInt32Value()],
+                sub.GetReflection()->GetInt32(sub, foreign_c_));
     }
     EXPECT_EQ(size, 2);
   }
@@ -1641,65 +1654,39 @@
 
 void MapReflectionTester::ExpectClearViaReflection(const Message& message) {
   const Reflection* reflection = message.GetReflection();
-  // Map fields are empty.
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
+  for (absl::string_view name : kMapFields) {
+    const FieldDescriptor* field = F(name);
+    auto map = reflection->GetMap(message, field).value();
+    EXPECT_EQ(0, reflection->FieldSize(message, field));
+    EXPECT_TRUE(map.empty());
+    EXPECT_EQ(0, map.size());
+    EXPECT_EQ(map.begin(), map.end());
+  }
   EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message"))
                   ->IsMapValid());
 }
 
+void MapReflectionTester::ExpectClearViaReflectionIterator(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  for (absl::string_view name : kMapFields) {
+    const FieldDescriptor* field = F(name);
+    GenericConstMapRef map = reflection->GetMap(message, field).value();
+    EXPECT_TRUE(map.empty());
+    EXPECT_EQ(map.size(), 0);
+    EXPECT_EQ(map.begin(), map.end());
+
+    int count = 0;
+    for (auto entry : map) {
+      (void)entry;
+      ++count;
+    }
+    EXPECT_EQ(count, 0);
+  }
+}
+
 void MapReflectionTester::ExpectClearViaReflectionIterator(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_int32")) ==
-              reflection->ConstMapEnd(message, F("map_int32_int32")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int64_int64")) ==
-              reflection->ConstMapEnd(message, F("map_int64_int64")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_uint32_uint32")) ==
-              reflection->ConstMapEnd(message, F("map_uint32_uint32")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_uint64_uint64")) ==
-              reflection->ConstMapEnd(message, F("map_uint64_uint64")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sint32_sint32")) ==
-              reflection->ConstMapEnd(message, F("map_sint32_sint32")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sint64_sint64")) ==
-              reflection->ConstMapEnd(message, F("map_sint64_sint64")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_fixed32_fixed32")) ==
-              reflection->ConstMapEnd(message, F("map_fixed32_fixed32")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_fixed64_fixed64")) ==
-              reflection->ConstMapEnd(message, F("map_fixed64_fixed64")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sfixed32_sfixed32")) ==
-              reflection->ConstMapEnd(message, F("map_sfixed32_sfixed32")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sfixed64_sfixed64")) ==
-              reflection->ConstMapEnd(message, F("map_sfixed64_sfixed64")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_float")) ==
-              reflection->ConstMapEnd(message, F("map_int32_float")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_double")) ==
-              reflection->ConstMapEnd(message, F("map_int32_double")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_bool_bool")) ==
-              reflection->ConstMapEnd(message, F("map_bool_bool")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_string_string")) ==
-              reflection->ConstMapEnd(message, F("map_string_string")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_bytes")) ==
-              reflection->ConstMapEnd(message, F("map_int32_bytes")));
-  EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_enum")) ==
-              reflection->ConstMapEnd(message, F("map_int32_enum")));
-  EXPECT_TRUE(
-      reflection->ConstMapBegin(message, F("map_int32_foreign_message")) ==
-      reflection->ConstMapEnd(message, F("map_int32_foreign_message")));
+  ExpectClearViaReflectionIterator(*message);
 }
 
 }  // namespace protobuf
diff --git a/src/google/protobuf/reflection_tester.h b/src/google/protobuf/reflection_tester.h
index bcd2445..0312ab7 100644
--- a/src/google/protobuf/reflection_tester.h
+++ b/src/google/protobuf/reflection_tester.h
@@ -30,40 +30,75 @@
   void SetMapFieldsViaReflection(Message* message);
   void SetMapFieldsViaMapReflection(Message* message);
   void ClearMapFieldsViaReflection(Message* message);
+  void ClearMapFieldsViaMapReflection(Message* message);
   void ModifyMapFieldsViaReflection(Message* message);
   void RemoveLastMapsViaReflection(Message* message);
   void ReleaseLastMapsViaReflection(Message* message);
   void SwapMapsViaReflection(Message* message);
+  void SwapMapsViaMapReflection(Message* message1, Message* message2);
+  void AssignMapsViaMapReflection(Message* dst, Message* src);
+  void EraseMapValuesViaMapReflectionIterator(Message* message);
   void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message);
   void ExpectMapFieldsSetViaReflection(const Message& message);
   void ExpectMapFieldsSetViaReflectionIterator(Message* message);
+  void ExpectMapFieldsSetViaReflectionIterator(const Message& message);
   void ExpectClearViaReflection(const Message& message);
   void ExpectClearViaReflectionIterator(Message* message);
-  void GetMapValueViaMapReflection(Message* message,
-                                   absl::string_view field_name,
-                                   const MapKey& map_key, MapValueRef* map_val);
+  void ExpectClearViaReflectionIterator(const Message& message);
   void DeleteMapValueViaMapReflection(Message* message,
                                       absl::string_view field_name,
-                                      const MapKey& map_key);
+                                      MapKey map_key);
   Message* GetMapEntryViaReflection(Message* message,
                                     absl::string_view field_name, int index);
-  MapIterator MapBegin(Message* message, absl::string_view field_name);
-  MapIterator MapEnd(Message* message, absl::string_view field_name);
-  ConstMapIterator ConstMapBegin(const Message* message,
-                                 absl::string_view field_name);
-  ConstMapIterator ConstMapEnd(const Message* message,
-                               absl::string_view field_name);
+
+  bool InsertOrLookupMapValue(Message* message, absl::string_view field_name,
+                              const MapKey& map_key, MapValueRef* map_val) {
+    auto res = message->GetReflection()
+                   ->MutableMap(message, F(field_name))
+                   .value()
+                   .try_emplace(map_key);
+    if (!res.ok()) return false;
+    *map_val = res->iter->value();
+    return res->inserted;
+  }
+
+  bool LookupMapValue(Message* message, absl::string_view field_name,
+                      const MapKey& map_key,
+                      MapValueConstRef* map_value_const_ref) {
+    return LookupMapValue(*message, field_name, map_key, map_value_const_ref);
+  }
+
+  bool LookupMapValue(const Message& message, absl::string_view field_name,
+                      const MapKey& map_key,
+                      MapValueConstRef* map_value_const_ref) {
+    auto map = message.GetReflection()->GetMap(message, F(field_name));
+    if (!map.ok()) return false;
+    auto it = map->find(map_key);
+    if (it == map->end()) return false;
+    *map_value_const_ref = it->value();
+    return true;
+  }
+
+  bool IsRepeatedFieldValid(const Message& message,
+                            absl::string_view field_name) {
+    const internal::MapFieldBase& map_field =
+        message.GetReflection()->GetRaw<internal::MapFieldBase>(message,
+                                                                F(field_name));
+    return map_field.IsRepeatedFieldValid();
+  }
+
   int MapSize(const Message& message, absl::string_view field_name);
 
   static absl::optional<MapValueConstRef> LookupMapValue(
       const Reflection& reflection, const Message& message,
       const FieldDescriptor& descriptor, const MapKey& map_key) {
-    MapValueConstRef map_val_const;
-    if (reflection.LookupMapValue(message, &descriptor, map_key,
-                                  &map_val_const)) {
-      return map_val_const;
+    auto map = reflection.GetMap(message, &descriptor);
+    if (!map.ok()) return absl::nullopt;
+    auto it = map->find(map_key);
+    if (it == map->end()) {
+      return absl::nullopt;
     }
-    return absl::nullopt;
+    return it->value();
   }
 
   static std::string long_string() {
diff --git a/src/google/protobuf/reflection_visit_field_info.h b/src/google/protobuf/reflection_visit_field_info.h
index c0da446..cf74a6e 100644
--- a/src/google/protobuf/reflection_visit_field_info.h
+++ b/src/google/protobuf/reflection_visit_field_info.h
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "absl/log/absl_check.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/arenastring.h"
@@ -1252,7 +1253,7 @@
 // Dispatches based on key type to instantiate a right KeyInfo, then calls
 // MapDynamicFieldVisitValue to dispatch on the value type.
 template <typename MapValueRefT, typename MapFieldCallback>
-void MapDynamicFieldVisitKey(const MapKey& key, MapValueRefT& value,
+void MapDynamicFieldVisitKey(const MapKey& key, MapValueRefT value,
                              const MapFieldCallback& user_cb) {
   switch (key.type()) {
 #define PROTOBUF_HANDLE_MAP_KEY_CASE(NAME, CPPTYPE)                            \
@@ -1284,14 +1285,8 @@
   constexpr MapDynamicFieldInfo(const Reflection* r, MessageT& m,
                                 const FieldDescriptor* f,
                                 const FieldDescriptor* key_f,
-                                const FieldDescriptor* val_f,
-                                const MapFieldBase& map_field)
-      : reflection(r),
-        message(m),
-        field(f),
-        key(key_f),
-        value(val_f),
-        const_map_field(map_field) {
+                                const FieldDescriptor* val_f)
+      : reflection(r), message(m), field(f), key(key_f), value(val_f) {
     ABSL_DCHECK(f->is_map());
     ABSL_DCHECK_NE(key_f, nullptr);
     ABSL_DCHECK_NE(val_f, nullptr);
@@ -1300,7 +1295,9 @@
   int number() const { return field->number(); }
   FieldDescriptor::Type key_type() const { return key->type(); }
   FieldDescriptor::Type value_type() const { return value->type(); }
-  int size() const { return const_map_field.size(); }
+  int size() const {
+    return static_cast<int>(reflection->GetMap(message, field).value().size());
+  }
 
   // go/ranked-overloads for the rationale.
   struct Rank0 {};
@@ -1310,40 +1307,30 @@
   template <typename T, typename Callback,
             typename = std::enable_if_t<!std::is_const_v<T>>>
   static void VisitElementsImpl(T& msg, const Reflection* reflection,
-                                const FieldDescriptor* field,
-                                const MapFieldBase&, Callback&& cb, Rank1) {
-    auto& map_field =
-        DynamicFieldInfoHelper<false>::template Mutable<MapFieldBase>(
-            reflection, msg, field);
-    const Descriptor* descriptor = field->message_type();
-    MapIterator begin(&map_field, descriptor), end(&map_field, descriptor);
-    map_field.MapBegin(&begin);
-    map_field.MapEnd(&end);
-
-    for (auto it = begin; it != end; ++it) {
-      MapDynamicFieldVisitKey(it.GetKey(), *it.MutableValueRef(), cb);
+                                const FieldDescriptor* field, Callback&& cb,
+                                Rank1) {
+    auto map = reflection->MutableMap(&msg, field);
+    ABSL_DCHECK(map.ok());
+    for (auto entry : *map) {
+      MapDynamicFieldVisitKey(entry.key(), entry.value(), cb);
     }
   }
 
   // Fallback version otherwise.
   template <typename T, typename Callback>
-  static void VisitElementsImpl(T& msg, const Reflection*,
-                                const FieldDescriptor* field,
-                                const MapFieldBase& map_field, Callback&& cb,
+  static void VisitElementsImpl(T& msg, const Reflection* ref,
+                                const FieldDescriptor* field, Callback&& cb,
                                 Rank0) {
-    const Descriptor* descriptor = field->message_type();
-    ConstMapIterator begin(&map_field, descriptor), end(&map_field, descriptor);
-    map_field.ConstMapBegin(&begin);
-    map_field.ConstMapEnd(&end);
-
-    for (auto it = begin; it != end; ++it) {
-      MapDynamicFieldVisitKey(it.GetKey(), it.GetValueRef(), cb);
+    auto map = ref->GetMap(msg, field);
+    ABSL_DCHECK(map.ok());
+    for (auto entry : *map) {
+      MapDynamicFieldVisitKey(entry.key(), entry.value(), cb);
     }
   }
 
   template <typename MapFieldCallback>
   void VisitElements(MapFieldCallback&& cb) const {
-    VisitElementsImpl(message, reflection, field, const_map_field,
+    VisitElementsImpl(message, reflection, field,
                       static_cast<MapFieldCallback&&>(cb), Rank1{});
   }
 
@@ -1367,7 +1354,6 @@
   const FieldDescriptor* field;
   const FieldDescriptor* key;
   const FieldDescriptor* value;
-  const MapFieldBase& const_map_field;
 };
 
 }  // namespace internal
diff --git a/src/google/protobuf/reflection_visit_fields.h b/src/google/protobuf/reflection_visit_fields.h
index 6eb2f52..8084e1f 100644
--- a/src/google/protobuf/reflection_visit_fields.h
+++ b/src/google/protobuf/reflection_visit_fields.h
@@ -8,6 +8,7 @@
 #include "absl/base/attributes.h"
 #include "absl/base/optimization.h"
 #include "absl/log/absl_check.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/cord.h"
 #include "google/protobuf/descriptor.h"
 #include "google/protobuf/descriptor.pb.h"
@@ -135,25 +136,23 @@
         PROTOBUF_HANDLE_REPEATED_CASE(SINT32, int32_t, SInt32);
         PROTOBUF_HANDLE_REPEATED_CASE(SINT64, int64_t, SInt64);
 
-#define PROTOBUF_HANDLE_REPEATED_PTR_CASE(TYPE, CPPTYPE, NAME)                 \
-  case FieldDescriptor::TYPE_##TYPE: {                                         \
-    if (ABSL_PREDICT_TRUE(!field->is_map())) {                                 \
-      /* Handle repeated fields. */                                            \
-      const auto& rep =                                                        \
-          reflection->GetRaw<RepeatedPtrField<CPPTYPE>>(message, field);       \
-      if (rep.size() == 0) continue;                                           \
-      func(internal::Repeated##NAME##DynamicFieldInfo<MessageT>{               \
-          reflection, message, field, rep});                                   \
-    } else {                                                                   \
-      /* Handle map fields. */                                                 \
-      const auto& map = reflection->GetRaw<MapFieldBase>(message, field);      \
-      if (map.size() == 0) continue; /* NOLINT */                              \
-      const Descriptor* desc = field->message_type();                          \
-      func(internal::MapDynamicFieldInfo<MessageT>{reflection, message, field, \
-                                                   desc->map_key(),            \
-                                                   desc->map_value(), map});   \
-    }                                                                          \
-    break;                                                                     \
+#define PROTOBUF_HANDLE_REPEATED_PTR_CASE(TYPE, CPPTYPE, NAME)              \
+  case FieldDescriptor::TYPE_##TYPE: {                                      \
+    if (ABSL_PREDICT_TRUE(!field->is_map())) {                              \
+      /* Handle repeated fields. */                                         \
+      const auto& rep =                                                     \
+          reflection->GetRaw<RepeatedPtrField<CPPTYPE>>(message, field);    \
+      if (rep.size() == 0) continue;                                        \
+      func(internal::Repeated##NAME##DynamicFieldInfo<MessageT>{            \
+          reflection, message, field, rep});                                \
+    } else {                                                                \
+      /* Handle map fields. */                                              \
+      if (reflection->GetMap(message, field)->empty()) continue;            \
+      const Descriptor* desc = field->message_type();                       \
+      func(internal::MapDynamicFieldInfo<MessageT>{                         \
+          reflection, message, field, desc->map_key(), desc->map_value()}); \
+    }                                                                       \
+    break;                                                                  \
   }
 
         PROTOBUF_HANDLE_REPEATED_PTR_CASE(MESSAGE, Message, Message);
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 5d267dd..f1d170d 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -2747,14 +2747,14 @@
     const Descriptor* map_entry_desc = field->message_type();
     const Message* prototype =
         reflection->GetMessageFactory()->GetPrototype(map_entry_desc);
-    all_entries.reserve(reflection->MapSize(message, field));
-    owned_entries.reserve(reflection->MapSize(message, field));
-    for (ConstMapIterator iter = reflection->ConstMapBegin(&message, field);
-         iter != reflection->ConstMapEnd(&message, field); ++iter) {
+    auto map = *reflection->GetMap(message, field);
+    all_entries.reserve(map.size());
+    owned_entries.reserve(map.size());
+    for (auto entry : map) {
       std::unique_ptr<Message> map_entry_message =
           absl::WrapUnique(prototype->New());
-      CopyKey(iter.GetKey(), map_entry_message.get(), map_entry_desc->field(0));
-      CopyValue(iter.GetValueRef(), map_entry_message.get(),
+      CopyKey(entry.key(), map_entry_message.get(), map_entry_desc->field(0));
+      CopyValue(entry.value(), map_entry_message.get(),
                 map_entry_desc->field(1));
       all_entries.push_back(map_entry_message.get());
       owned_entries.push_back(std::move(map_entry_message));
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index ae685a4..8f8333e 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -1081,21 +1081,19 @@
   ABSL_DCHECK_EQ(repeated_field_comparison_, AS_LIST);
   const Reflection* reflection1 = message1.GetReflection();
   const Reflection* reflection2 = message2.GetReflection();
-  const int count1 = reflection1->MapSize(message1, map_field);
-  const int count2 = reflection2->MapSize(message2, map_field);
+  GenericConstMapRef map1 = *reflection1->GetMap(message1, map_field);
+  GenericConstMapRef map2 = *reflection2->GetMap(message2, map_field);
   const bool treated_as_subset = IsTreatedAsSubset(map_field);
-  if (count1 != count2 && !treated_as_subset) {
+  if (map1.size() != map2.size() && !treated_as_subset) {
     return false;
   }
-  if (count1 > count2) {
+  if (map1.size() > map2.size()) {
     return false;
   }
 
   // First pass: check whether the same keys are present.
-  for (ConstMapIterator it = reflection1->ConstMapBegin(&message1, map_field),
-                        it_end = reflection1->ConstMapEnd(&message1, map_field);
-       it != it_end; ++it) {
-    if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) {
+  for (auto entry1 : map1) {
+    if (!map2.contains(entry1.key())) {
       return false;
     }
   }
@@ -1103,21 +1101,16 @@
   // Second pass: compare values for matching keys.
   const FieldDescriptor* val_des = map_field->message_type()->map_value();
   switch (val_des->cpp_type()) {
-#define HANDLE_TYPE(CPPTYPE, METHOD, COMPAREMETHOD)                           \
-  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                                  \
-    for (ConstMapIterator                                                     \
-             it = reflection1->ConstMapBegin(&message1, map_field),           \
-             it_end = reflection1->ConstMapEnd(&message1, map_field);         \
-         it != it_end; ++it) {                                                \
-      MapValueConstRef value2;                                                \
-      reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2); \
-      if (!comparator->Compare##COMPAREMETHOD(*val_des,                       \
-                                              it.GetValueRef().Get##METHOD(), \
-                                              value2.Get##METHOD())) {        \
-        return false;                                                         \
-      }                                                                       \
-    }                                                                         \
-    break;                                                                    \
+#define HANDLE_TYPE(CPPTYPE, METHOD, COMPAREMETHOD)                            \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE: {                                   \
+    for (auto entry1 : map1) {                                                 \
+      MapValueConstRef value2 = map2.find(entry1.key())->value();              \
+      if (!comparator->Compare##COMPAREMETHOD(                                 \
+              *val_des, entry1.value().Get##METHOD(), value2.Get##METHOD())) { \
+        return false;                                                          \
+      }                                                                        \
+    }                                                                          \
+    break;                                                                     \
   }
     HANDLE_TYPE(INT32, Int32Value, Int32);
     HANDLE_TYPE(INT64, Int64Value, Int64);
@@ -1130,15 +1123,12 @@
     HANDLE_TYPE(ENUM, EnumValue, Int32);
 #undef HANDLE_TYPE
     case FieldDescriptor::CPPTYPE_MESSAGE: {
-      for (ConstMapIterator it =
-               reflection1->ConstMapBegin(&message1, map_field);
-           it != reflection1->ConstMapEnd(&message1, map_field); ++it) {
-        if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) {
+      for (auto entry1 : map1) {
+        auto it2 = map2.find(entry1.key());
+        if (it2 == map2.end()) {
           return false;
         }
         bool compare_result;
-        MapValueConstRef value2;
-        reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2);
         // Append currently compared field to the end of parent_fields.
         SpecificField specific_value_field;
         specific_value_field.message1 = &message1;
@@ -1147,8 +1137,8 @@
         specific_value_field.field = val_des;
         parent_fields->push_back(specific_value_field);
         compare_result =
-            Compare(it.GetValueRef().GetMessageValue(),
-                    value2.GetMessageValue(), false, parent_fields);
+            Compare(entry1.value().GetMessageValue(),
+                    it2->value().GetMessageValue(), false, parent_fields);
         parent_fields->pop_back();
         if (!compare_result) {
           return false;
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 7cb447c..d78ee57 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -22,6 +22,7 @@
 #include "absl/base/optimization.h"
 #include "absl/log/absl_check.h"
 #include "absl/log/absl_log.h"
+#include "absl/status/statusor.h"
 #include "absl/strings/cord.h"
 #include "absl/strings/string_view.h"
 #include "google/protobuf/class_data.h"
@@ -1141,9 +1142,9 @@
                                      const Reflection* reflection,
                                      const FieldDescriptor* field) {
     std::vector<MapKey> sorted_key_list;
-    for (ConstMapIterator it = reflection->ConstMapBegin(&message, field);
-         it != reflection->ConstMapEnd(&message, field); ++it) {
-      sorted_key_list.push_back(it.GetKey());
+    auto map = *reflection->GetMap(message, field);
+    for (auto entry : map) {
+      sorted_key_list.push_back(entry.key());
     }
     MapKeyComparator comparator;
     std::sort(sorted_key_list.begin(), sorted_key_list.end(), comparator);
@@ -1229,22 +1230,20 @@
     const MapFieldBase* map_field =
         message_reflection->GetMapData(message, field);
     if (map_field->IsMapValid()) {
+      GenericConstMapRef map = *message_reflection->GetMap(message, field);
       if (stream->IsSerializationDeterministic()) {
         std::vector<MapKey> sorted_key_list =
             MapKeySorter::SortKey(message, message_reflection, field);
         for (std::vector<MapKey>::iterator it = sorted_key_list.begin();
              it != sorted_key_list.end(); ++it) {
-          MapValueConstRef map_value;
-          message_reflection->LookupMapValue(message, field, *it, &map_value);
+          MapValueConstRef map_value = map.find(*it)->value();
           target =
               InternalSerializeMapEntry(field, *it, map_value, target, stream);
         }
       } else {
-        for (ConstMapIterator it =
-                 message_reflection->ConstMapBegin(&message, field);
-             it != message_reflection->ConstMapEnd(&message, field); ++it) {
-          target = InternalSerializeMapEntry(field, it.GetKey(),
-                                             it.GetValueRef(), target, stream);
+        for (auto entry : map) {
+          target = InternalSerializeMapEntry(field, entry.key(), entry.value(),
+                                             target, stream);
         }
       }
 
@@ -1500,7 +1499,7 @@
       const MapFieldBase* map_field =
           message_reflection->GetMapData(message, field);
       if (map_field->IsMapValid()) {
-        count = FromIntSize(map_field->size());
+        count = map_field->GetMap().size();
       } else {
         count = FromIntSize(message_reflection->FieldSize(message, field));
       }
@@ -1621,15 +1620,13 @@
     const MapFieldBase* map_field =
         message_reflection->GetMapData(message, field);
     if (map_field->IsMapValid()) {
-      ConstMapIterator iter(&message, field);
-      ConstMapIterator end(&message, field);
       const FieldDescriptor* key_field = field->message_type()->field(0);
       const FieldDescriptor* value_field = field->message_type()->field(1);
-      for (map_field->ConstMapBegin(&iter), map_field->ConstMapEnd(&end);
-           iter != end; ++iter) {
+      auto map = *message_reflection->GetMap(message, field);
+      for (auto entry : map) {
         size_t size = kMapEntryTagByteSize;
-        size += MapKeyDataOnlyByteSize(key_field, iter.GetKey());
-        size += MapValueRefDataOnlyByteSize(value_field, iter.GetValueRef());
+        size += MapKeyDataOnlyByteSize(key_field, entry.key());
+        size += MapValueRefDataOnlyByteSize(value_field, entry.value());
         data_size += WireFormatLite::LengthDelimitedSize(size);
       }
       return data_size;