diff --git a/docs/reference/matchers.md b/docs/reference/matchers.md
index 243e3f9516..48978627b3 100644
--- a/docs/reference/matchers.md
+++ b/docs/reference/matchers.md
@@ -208,6 +208,15 @@ messages, you can use:
 | `Pointee(m)`              | `argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`. |
 | `Pointer(m)`              | `argument` (either a smart pointer or a raw pointer) contains a pointer that matches `m`. `m` will match against the raw pointer regardless of the type of `argument`. |
 | `WhenDynamicCastTo<T>(m)` | when `argument` is passed through `dynamic_cast<T>()`, it matches matcher `m`. |
+| `WhenStaticCastTo<T>(m)`  | when `argument` is passed through `static_cast<T>()`, it matches matcher `m`.  |
+
+`WhenDynamicCast` can be used for safely checking the dynamic type of an object
+and navigating the inheritance tree of an object.
+
+`WhenStaticCast` is primarily used to check and argument which was type-erased
+as `void*`. It can also be used as an unsafe replacement of `WhenDynamicCast`
+in environemnts without RTTI, or for pointer-based type punning by chaining
+a cast to `void*` and then another pointer (equivalent to `reinterpret_cast`).
 
 ## Multi-argument Matchers {#MultiArgMatchers}
 
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index e979544c72..d9c6ef3da0 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -2022,17 +2022,10 @@ class PointerMatcher {
   const InnerMatcher matcher_;
 };
 
-#if GTEST_HAS_RTTI
-// Implements the WhenDynamicCastTo<T>(m) matcher that matches a pointer or
-// reference that matches inner_matcher when dynamic_cast<T> is applied.
-// The result of dynamic_cast<To> is forwarded to the inner matcher.
-// If To is a pointer and the cast fails, the inner matcher will receive NULL.
-// If To is a reference and the cast fails, this matcher returns false
-// immediately.
-template <typename To>
-class WhenDynamicCastToMatcherBase {
+template <typename To, typename Caster>
+class WhenCastToMatcherBase {
  public:
-  explicit WhenDynamicCastToMatcherBase(const Matcher<To>& matcher)
+  explicit WhenCastToMatcherBase(const Matcher<To>& matcher)
       : matcher_(matcher) {}
 
   void DescribeTo(::std::ostream* os) const {
@@ -2045,6 +2038,12 @@ class WhenDynamicCastToMatcherBase {
     matcher_.DescribeNegationTo(os);
   }
 
+  template <typename From>
+  bool MatchAndExplain(From&& from, MatchResultListener* listener) const {
+    decltype(auto) to = Caster::template Cast<To>(from);
+    return MatchPrintAndExplain(to, this->matcher_, listener);
+  }
+
  protected:
   const Matcher<To> matcher_;
 
@@ -2052,32 +2051,40 @@ class WhenDynamicCastToMatcherBase {
 
  private:
   static void GetCastTypeDescription(::std::ostream* os) {
-    *os << "when dynamic_cast to " << GetToName() << ", ";
+    *os << "when " << Caster::Name << " to " << GetToName() << ", ";
   }
 };
 
-// Primary template.
-// To is a pointer. Cast and forward the result.
-template <typename To>
-class WhenDynamicCastToMatcher : public WhenDynamicCastToMatcherBase<To> {
+#if GTEST_HAS_RTTI
+class DynamicCaster {
  public:
-  explicit WhenDynamicCastToMatcher(const Matcher<To>& matcher)
-      : WhenDynamicCastToMatcherBase<To>(matcher) {}
+  static constexpr const char* Name = "dynamic_cast";
 
-  template <typename From>
-  bool MatchAndExplain(From from, MatchResultListener* listener) const {
-    To to = dynamic_cast<To>(from);
-    return MatchPrintAndExplain(to, this->matcher_, listener);
+  template <typename To, typename From>
+  static To Cast(From&& from) {
+    return dynamic_cast<To>(from);
   }
 };
 
+// Implements the WhenDynamicCastTo<T>(m) matcher that matches a pointer or
+// reference that matches inner_matcher when dynamic_cast<T> is applied.
+// The result of dynamic_cast<To> is forwarded to the inner matcher.
+
+// To is a pointer. Cast and forward the result, which might be nullptr.
+template <typename To>
+class WhenDynamicCastToMatcher
+    : public WhenCastToMatcherBase<To, DynamicCaster> {
+ public:
+  using WhenCastToMatcherBase<To, DynamicCaster>::WhenCastToMatcherBase;
+};
+
 // Specialize for references.
 // In this case we return false if the dynamic_cast fails.
 template <typename To>
-class WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> {
+class WhenDynamicCastToMatcher<To&>
+    : public WhenCastToMatcherBase<To&, DynamicCaster> {
  public:
-  explicit WhenDynamicCastToMatcher(const Matcher<To&>& matcher)
-      : WhenDynamicCastToMatcherBase<To&>(matcher) {}
+  using WhenCastToMatcherBase<To&, DynamicCaster>::WhenCastToMatcherBase;
 
   template <typename From>
   bool MatchAndExplain(From& from, MatchResultListener* listener) const {
@@ -2092,6 +2099,25 @@ class WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> {
 };
 #endif  // GTEST_HAS_RTTI
 
+// Implements the WhenStaticCastTo<T>(m) matcher that matches a pointer or
+// reference that matches inner_matcher when static_cast<T> is applied.
+// The result of static_cast<To> is forwarded to the inner matcher.
+class StaticCaster {
+ public:
+  static constexpr const char* Name = "static_cast";
+
+  template <typename To, typename From>
+  static To Cast(From&& from) {
+    return static_cast<To>(from);
+  }
+};
+
+template <typename To>
+class WhenStaticCastToMatcher : public WhenCastToMatcherBase<To, StaticCaster> {
+ public:
+  using WhenCastToMatcherBase<To, StaticCaster>::WhenCastToMatcherBase;
+};
+
 // Implements the Field() matcher for matching a field (i.e. member
 // variable) of an object.
 template <typename Class, typename FieldType>
@@ -4424,6 +4450,16 @@ WhenDynamicCastTo(const Matcher<To>& inner_matcher) {
 }
 #endif  // GTEST_HAS_RTTI
 
+// Creates a matcher that matches a pointer or reference that matches
+// inner_matcher when static_cast<To> is applied.
+// The result of static_cast<To> is forwarded to the inner matcher.
+template <typename To>
+inline PolymorphicMatcher<internal::WhenStaticCastToMatcher<To>>
+WhenStaticCastTo(const Matcher<To>& inner_matcher) {
+  return MakePolymorphicMatcher(
+      internal::WhenStaticCastToMatcher<To>(inner_matcher));
+}
+
 // Creates a matcher that matches an object whose given field matches
 // 'matcher'.  For example,
 //   Field(&Foo::number, Ge(5))
diff --git a/googlemock/test/gmock-matchers-comparisons_test.cc b/googlemock/test/gmock-matchers-comparisons_test.cc
index a331aeca96..73307a2101 100644
--- a/googlemock/test/gmock-matchers-comparisons_test.cc
+++ b/googlemock/test/gmock-matchers-comparisons_test.cc
@@ -2333,6 +2333,41 @@ TEST(WhenDynamicCastToTest, BadReference) {
 }
 #endif  // GTEST_HAS_RTTI
 
+TEST(WhenStaticCastToTest, VoidPointer) {
+  Derived derived;
+  derived.i = 4;
+  void* as_void_ptr = &derived;
+  EXPECT_THAT(as_void_ptr, WhenStaticCastTo<Derived*>(Pointee(FieldIIs(4))));
+  EXPECT_THAT(as_void_ptr,
+              WhenStaticCastTo<Derived*>(Pointee(Not(FieldIIs(5)))));
+}
+
+TEST(WhenStaticCastToTest, Inheritance) {
+  Derived derived;
+  EXPECT_THAT(derived, WhenStaticCastTo<const Base&>(_));
+  EXPECT_THAT(&derived, WhenStaticCastTo<Base*>(_));
+  EXPECT_THAT(derived, WhenStaticCastTo<const Derived&>(_));
+  EXPECT_THAT(&derived, WhenStaticCastTo<Derived*>(_));
+  // These will not compile because direct sidecasts are invalid
+  // EXPECT_THAT(derived, WhenStaticCastTo<const OtherDerived&>(_));
+  // EXPECT_THAT(&derived, WhenStaticCastTo<OtherDerived*>(_));
+
+  Base& as_base_ref = derived;
+  EXPECT_THAT(as_base_ref, WhenStaticCastTo<const Base&>(_));
+  EXPECT_THAT(&as_base_ref, WhenStaticCastTo<Base*>(_));
+  EXPECT_THAT(as_base_ref, WhenStaticCastTo<const Derived&>(_));
+  EXPECT_THAT(&as_base_ref, WhenStaticCastTo<Derived*>(_));
+  // These will compile and match, but are not safe
+  EXPECT_THAT(as_base_ref, WhenStaticCastTo<const OtherDerived&>(_));
+  EXPECT_THAT(&as_base_ref, WhenStaticCastTo<OtherDerived*>(_));
+}
+
+TEST(WhenStaticCastToTest, Punning) {
+  std::uint32_t u32 = 0xCCCCCCCC;
+  EXPECT_THAT(&u32, WhenStaticCastTo<void*>(
+                        WhenStaticCastTo<std::uint8_t*>(Pointee(Eq(0xCC)))));
+}
+
 class DivisibleByImpl {
  public:
   explicit DivisibleByImpl(int a_divider) : divider_(a_divider) {}