diff --git a/src/json.hpp b/src/json.hpp
index d238a28f..f7101d14 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -3073,8 +3073,11 @@ class basic_json
 
     @since version 2.1.0
     */
-    template <typename T,
-              detail::enable_if_t<std::is_same<T, basic_json_t>::value, int> = 0>
+    template <
+        typename T,
+        detail::enable_if_t<std::is_same<typename std::remove_const<T>::type,
+                                         basic_json_t>::value,
+                            int> = 0 >
     basic_json get() const
     {
         return *this;
@@ -3104,16 +3107,15 @@ class basic_json
             not detail::has_non_default_from_json<basic_json_t,
                     U>::value,
             int > = 0 >
-    // do we really want the uncvref ? if a user call get<int &>, shouldn't we
-    // static assert ?
-    // i know there is a special behaviour for boolean_t* and such
     U get() const noexcept(noexcept(JSONSerializer<U>::from_json(
                                         std::declval<const basic_json_t&>(), std::declval<U&>())))
     {
-        static_assert(std::is_default_constructible<U>::value and
-                      std::is_copy_constructible<U>::value,
-                      "Types must be DefaultConstructible and "
-                      "CopyConstructible when used with get");
+        // we cannot static_assert on T being non-const, because there is support
+        // for get<const basic_json_t>(), which is why we still need the uncvref
+        static_assert(not std::is_reference<T>::value, "get cannot be used with reference types, you might want to use get_ref");
+        static_assert(not std::is_pointer<T>::value, "get cannot be used with pointer types, you might want to use get_ptr");
+        static_assert(std::is_default_constructible<U>::value,
+                      "Types must be DefaultConstructible when used with get");
         U ret;
         JSONSerializer<U>::from_json(*this, ret);
         return ret;
@@ -3143,6 +3145,8 @@ class basic_json
                             int> = 0 >
     U get() const noexcept(noexcept(JSONSerializer<T>::from_json(std::declval<const basic_json_t&>())))
     {
+        static_assert(not std::is_reference<T>::value, "get cannot be used with reference types, you might want to use get_ref");
+        static_assert(not std::is_pointer<T>::value, "get cannot be used with pointer types, you might want to use get_ptr");
         return JSONSerializer<T>::from_json(*this);
     }
 
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 9510cddc..65860c4d 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -3073,8 +3073,11 @@ class basic_json
 
     @since version 2.1.0
     */
-    template <typename T,
-              detail::enable_if_t<std::is_same<T, basic_json_t>::value, int> = 0>
+    template <
+        typename T,
+        detail::enable_if_t<std::is_same<typename std::remove_const<T>::type,
+                                         basic_json_t>::value,
+                            int> = 0 >
     basic_json get() const
     {
         return *this;
@@ -3104,16 +3107,14 @@ class basic_json
             not detail::has_non_default_from_json<basic_json_t,
                     U>::value,
             int > = 0 >
-    // do we really want the uncvref ? if a user call get<int &>, shouldn't we
-    // static assert ?
-    // i know there is a special behaviour for boolean_t* and such
     U get() const noexcept(noexcept(JSONSerializer<U>::from_json(
                                         std::declval<const basic_json_t&>(), std::declval<U&>())))
     {
-        static_assert(std::is_default_constructible<U>::value and
-                      std::is_copy_constructible<U>::value,
-                      "Types must be DefaultConstructible and "
-                      "CopyConstructible when used with get");
+        // we cannot static_assert on T being non-const, because there is support
+        // for get<const basic_json_t>(), which is why we still need the uncvref
+        static_assert(not std::is_reference<T>::value, "get cannot be used with reference types, you might want to use get_ref");
+        static_assert(std::is_default_constructible<U>::value,
+                      "Types must be DefaultConstructible when used with get");
         U ret;
         JSONSerializer<U>::from_json(*this, ret);
         return ret;
@@ -3143,6 +3144,7 @@ class basic_json
                             int> = 0 >
     U get() const noexcept(noexcept(JSONSerializer<T>::from_json(std::declval<const basic_json_t&>())))
     {
+        static_assert(not std::is_reference<T>::value, "get cannot be used with reference types, you might want to use get_ref");
         return JSONSerializer<T>::from_json(*this);
     }