diff --git a/src/json.hpp b/src/json.hpp
index 508dd805..f51c85ad 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -3255,7 +3255,7 @@ class basic_json
 
     @tparam ThisType will be deduced as `basic_json` or `const basic_json`
 
-    @throw std::domain_error if ReferenceType does not match underlying value
+    @throw type_error.303 if ReferenceType does not match underlying value
     type of the current JSON
     */
     template<typename ReferenceType, typename ThisType>
@@ -3272,8 +3272,7 @@ class basic_json
             return *ptr;
         }
 
-        JSON_THROW(std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
-                                     obj.type_name()));
+        JSON_THROW(type_error(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name()));
     }
 
   public:
@@ -3554,8 +3553,8 @@ class basic_json
     reference type @a ReferenceType fits to the JSON value; throws
     std::domain_error otherwise
 
-    @throw std::domain_error in case passed type @a ReferenceType is
-    incompatible with the stored JSON value
+    @throw type_error.303 in case passed type @a ReferenceType is incompatible
+    with the stored JSON value
 
     @complexity Constant.
 
@@ -3646,8 +3645,8 @@ class basic_json
 
     @return reference to the element at index @a idx
 
-    @throw std::domain_error if the JSON value is not an array; example:
-    `"cannot use at() with string"`
+    @throw type_error.304 if the JSON value is not an array; example: `"cannot
+    use at() with string"`
     @throw std::out_of_range if the index @a idx is out of range of the array;
     that is, `idx >= size()`; example: `"array index 7 is out of range"`
 
@@ -3675,7 +3674,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
@@ -3689,8 +3688,8 @@ class basic_json
 
     @return const reference to the element at index @a idx
 
-    @throw std::domain_error if the JSON value is not an array; example:
-    `"cannot use at() with string"`
+    @throw type_error.304 if the JSON value is not an array; example: `"cannot
+    use at() with string"`
     @throw std::out_of_range if the index @a idx is out of range of the array;
     that is, `idx >= size()`; example: `"array index 7 is out of range"`
 
@@ -3718,7 +3717,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
@@ -3732,7 +3731,7 @@ class basic_json
 
     @return reference to the element at key @a key
 
-    @throw std::domain_error if the JSON value is not an object; example:
+    @throw type_error.304 if the JSON value is not an object; example:
     `"cannot use at() with boolean"`
     @throw std::out_of_range if the key @a key is is not stored in the object;
     that is, `find(key) == end()`; example: `"key "the fast" not found"`
@@ -3765,7 +3764,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
@@ -3779,7 +3778,7 @@ class basic_json
 
     @return const reference to the element at key @a key
 
-    @throw std::domain_error if the JSON value is not an object; example:
+    @throw type_error.304 if the JSON value is not an object; example:
     `"cannot use at() with boolean"`
     @throw std::out_of_range if the key @a key is is not stored in the object;
     that is, `find(key) == end()`; example: `"key "the fast" not found"`
@@ -3812,7 +3811,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 03d873af..1e136f2c 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -3255,7 +3255,7 @@ class basic_json
 
     @tparam ThisType will be deduced as `basic_json` or `const basic_json`
 
-    @throw std::domain_error if ReferenceType does not match underlying value
+    @throw type_error.303 if ReferenceType does not match underlying value
     type of the current JSON
     */
     template<typename ReferenceType, typename ThisType>
@@ -3272,8 +3272,7 @@ class basic_json
             return *ptr;
         }
 
-        JSON_THROW(std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
-                                     obj.type_name()));
+        JSON_THROW(type_error(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name()));
     }
 
   public:
@@ -3554,8 +3553,8 @@ class basic_json
     reference type @a ReferenceType fits to the JSON value; throws
     std::domain_error otherwise
 
-    @throw std::domain_error in case passed type @a ReferenceType is
-    incompatible with the stored JSON value
+    @throw type_error.303 in case passed type @a ReferenceType is incompatible
+    with the stored JSON value
 
     @complexity Constant.
 
@@ -3646,8 +3645,8 @@ class basic_json
 
     @return reference to the element at index @a idx
 
-    @throw std::domain_error if the JSON value is not an array; example:
-    `"cannot use at() with string"`
+    @throw type_error.304 if the JSON value is not an array; example: `"cannot
+    use at() with string"`
     @throw std::out_of_range if the index @a idx is out of range of the array;
     that is, `idx >= size()`; example: `"array index 7 is out of range"`
 
@@ -3675,7 +3674,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
@@ -3689,8 +3688,8 @@ class basic_json
 
     @return const reference to the element at index @a idx
 
-    @throw std::domain_error if the JSON value is not an array; example:
-    `"cannot use at() with string"`
+    @throw type_error.304 if the JSON value is not an array; example: `"cannot
+    use at() with string"`
     @throw std::out_of_range if the index @a idx is out of range of the array;
     that is, `idx >= size()`; example: `"array index 7 is out of range"`
 
@@ -3718,7 +3717,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
@@ -3732,7 +3731,7 @@ class basic_json
 
     @return reference to the element at key @a key
 
-    @throw std::domain_error if the JSON value is not an object; example:
+    @throw type_error.304 if the JSON value is not an object; example:
     `"cannot use at() with boolean"`
     @throw std::out_of_range if the key @a key is is not stored in the object;
     that is, `find(key) == end()`; example: `"key "the fast" not found"`
@@ -3765,7 +3764,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
@@ -3779,7 +3778,7 @@ class basic_json
 
     @return const reference to the element at key @a key
 
-    @throw std::domain_error if the JSON value is not an object; example:
+    @throw type_error.304 if the JSON value is not an object; example:
     `"cannot use at() with boolean"`
     @throw std::out_of_range if the key @a key is is not stored in the object;
     that is, `find(key) == end()`; example: `"key "the fast" not found"`
@@ -3812,7 +3811,7 @@ class basic_json
         }
         else
         {
-            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+            JSON_THROW(type_error(304, "cannot use at() with " + type_name()));
         }
     }
 
diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp
index a521e3c4..baea8f2a 100644
--- a/test/src/unit-element_access1.cpp
+++ b/test/src/unit-element_access1.cpp
@@ -76,77 +76,77 @@ TEST_CASE("element access 1")
                 {
                     json j_nonarray(json::value_t::null);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with null");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with null");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with null");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with null");
                 }
 
                 SECTION("boolean")
                 {
                     json j_nonarray(json::value_t::boolean);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with boolean");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with boolean");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with boolean");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with boolean");
                 }
 
                 SECTION("string")
                 {
                     json j_nonarray(json::value_t::string);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with string");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with string");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with string");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with string");
                 }
 
                 SECTION("object")
                 {
                     json j_nonarray(json::value_t::object);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with object");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with object");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with object");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with object");
                 }
 
                 SECTION("number (integer)")
                 {
                     json j_nonarray(json::value_t::number_integer);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number");
                 }
 
                 SECTION("number (unsigned)")
                 {
                     json j_nonarray(json::value_t::number_unsigned);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number");
                 }
 
                 SECTION("number (floating-point)")
                 {
                     json j_nonarray(json::value_t::number_float);
                     const json j_nonarray_const(j_nonarray);
-                    CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
-                    CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
+                    CHECK_THROWS_AS(j_nonarray.at(0), json::type_error);
+                    CHECK_THROWS_AS(j_nonarray_const.at(0), json::type_error);
 
-                    CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number");
-                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonarray.at(0), "[json.exception.type_error.304] cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonarray_const.at(0), "[json.exception.type_error.304] cannot use at() with number");
                 }
             }
         }
diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp
index 3c3122f1..c4de9d43 100644
--- a/test/src/unit-element_access2.cpp
+++ b/test/src/unit-element_access2.cpp
@@ -75,70 +75,70 @@ TEST_CASE("element access 2")
                 {
                     json j_nonobject(json::value_t::null);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with null");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with null");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null");
                 }
 
                 SECTION("boolean")
                 {
                     json j_nonobject(json::value_t::boolean);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with boolean");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with boolean");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean");
                 }
 
                 SECTION("string")
                 {
                     json j_nonobject(json::value_t::string);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with string");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with string");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string");
                 }
 
                 SECTION("array")
                 {
                     json j_nonobject(json::value_t::array);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with array");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with array");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array");
                 }
 
                 SECTION("number (integer)")
                 {
                     json j_nonobject(json::value_t::number_integer);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number");
                 }
 
                 SECTION("number (unsigned)")
                 {
                     json j_nonobject(json::value_t::number_unsigned);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number");
                 }
 
                 SECTION("number (floating-point)")
                 {
                     json j_nonobject(json::value_t::number_float);
                     const json j_nonobject_const(j_nonobject);
-                    CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
-                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
-                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
-                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
+                    CHECK_THROWS_AS(j_nonobject.at("foo"), json::type_error);
+                    CHECK_THROWS_AS(j_nonobject_const.at("foo"), json::type_error);
+                    CHECK_THROWS_WITH(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number");
+                    CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number");
                 }
             }
         }