diff --git a/regression-tests/pure2-print.cpp2 b/regression-tests/pure2-print.cpp2
index 23ec488d07..6b80d9cb7a 100644
--- a/regression-tests/pure2-print.cpp2
+++ b/regression-tests/pure2-print.cpp2
@@ -100,7 +100,7 @@ outer: @print type = {
     all: <Args...: type> (args...: Args) -> bool =
         (... && args);
 
-    y: (_: decltype(0)) = { }
+    y: (_: type_of(0)) = { }
 
 }
 
diff --git a/regression-tests/test-results/pure2-print.cpp b/regression-tests/test-results/pure2-print.cpp
index 40402c3393..47725b5735 100644
--- a/regression-tests/test-results/pure2-print.cpp
+++ b/regression-tests/test-results/pure2-print.cpp
@@ -72,7 +72,7 @@ CPP2_REQUIRES_ (cpp2::impl::cmp_greater_eq(sizeof...(Args),0u)) ;
     public: template<typename ...Args> [[nodiscard]] static auto all(Args const& ...args) -> bool;
 
 #line 103 "pure2-print.cpp2"
-    public: static auto y([[maybe_unused]] cpp2::impl::in<decltype(0)> unnamed_param_1) -> void;
+    public: static auto y([[maybe_unused]] cpp2::impl::in<CPP2_TYPEOF(0)> unnamed_param_1) -> void;
     public: outer() = default;
     public: outer(outer const&) = delete; /* No 'that' constructor, suppress copy */
     public: auto operator=(outer const&) -> void = delete;
@@ -203,7 +203,7 @@ requires (cpp2::impl::cmp_greater_eq(sizeof...(Args),0u)) {
         return (... && args);  }
 
 #line 103 "pure2-print.cpp2"
-    auto outer::y([[maybe_unused]] cpp2::impl::in<decltype(0)> unnamed_param_1) -> void{}
+    auto outer::y([[maybe_unused]] cpp2::impl::in<CPP2_TYPEOF(0)> unnamed_param_1) -> void{}
 
 #line 107 "pure2-print.cpp2"
 auto main() -> int{
diff --git a/regression-tests/test-results/pure2-print.cpp2.output b/regression-tests/test-results/pure2-print.cpp2.output
index 1c141deb84..2d49209242 100644
--- a/regression-tests/test-results/pure2-print.cpp2.output
+++ b/regression-tests/test-results/pure2-print.cpp2.output
@@ -147,7 +147,7 @@ outer:/* @print */ type =
 
     all: <Args...: type, >(in args...: Args, ) -> move bool = (... && args);
 
-    y:(in _: decltype(0), ) = 
+    y:(in _: type_of(0), ) = 
     {
     }
 }
diff --git a/source/parse.h b/source/parse.h
index 3e73a6d088..0a25b38d0f 100644
--- a/source/parse.h
+++ b/source/parse.h
@@ -1389,7 +1389,7 @@ struct type_id_node
     int                       dereference_cnt           = {};
     token const*              suspicious_initialization = {};
 
-    enum active : u8 { empty=0, decltype_, qualified, unqualified, function, keyword };
+    enum active : u8 { empty=0, postfix, qualified, unqualified, function, keyword };
     std::variant<
         std::monostate,
         std::unique_ptr<postfix_expression_node>,
@@ -1460,7 +1460,7 @@ struct type_id_node
         switch (id.index()) {
         break;case empty:
             return {};
-        break;case decltype_:
+        break;case postfix:
             return {};
         break;case qualified:
             return {};
@@ -1490,7 +1490,7 @@ struct type_id_node
         for (auto q : pc_qualifiers) {
             v.start(*q, depth+1);
         }
-        try_visit<decltype_  >(id, v, depth);
+        try_visit<postfix    >(id, v, depth);
         try_visit<qualified  >(id, v, depth);
         try_visit<unqualified>(id, v, depth);
         try_visit<function   >(id, v, depth);
@@ -2825,8 +2825,8 @@ auto type_id_node::to_string() const
     switch (id.index()) {
     break;case empty:
         ret += "_";
-    break;case decltype_:
-        ret += std::get<decltype_>(id)->to_string();
+    break;case postfix:
+        ret += std::get<postfix>(id)->to_string();
     break;case qualified:
         ret += std::get<qualified>(id)->to_string();
     break;case unqualified:
@@ -5157,7 +5157,7 @@ auto pretty_print_visualize(type_id_node const& n, int indent)
     }
 
     if (n.id.index() == type_id_node::empty) { ret += "_"; }
-    ret += try_pretty_print_visualize<type_id_node::decltype_  >(n.id, indent);
+    ret += try_pretty_print_visualize<type_id_node::postfix    >(n.id, indent);
     ret += try_pretty_print_visualize<type_id_node::qualified  >(n.id, indent);
     ret += try_pretty_print_visualize<type_id_node::unqualified>(n.id, indent);
     ret += try_pretty_print_visualize<type_id_node::function   >(n.id, indent);
@@ -6941,6 +6941,7 @@ class parser
 
 
     //G type-id:
+    //G     type-qualifier-seq? 'type_of'  '(' expression ')' is-type-constraint?
     //G     type-qualifier-seq? 'decltype' '(' expression ')' is-type-constraint?
     //G     type-qualifier-seq? qualified-id is-type-constraint?
     //G     type-qualifier-seq? unqualified-id is-type-constraint?
@@ -6985,11 +6986,13 @@ class parser
         }
 
         if (auto& c = curr();
-            c == "decltype"
+            c == "type_of"
+            || c == "decltype"
             )
         {
             if (
-                peek(1) && peek(1)->type() == lexeme::LeftParen
+                c == "decltype"
+                && peek(1) && peek(1)->type() == lexeme::LeftParen
                 && peek(2) && *peek(2) == "auto"
                 && peek(3) && peek(3)->type() == lexeme::RightParen)
             {
@@ -7008,11 +7011,11 @@ class parser
             {
                 n->pos = id->position();
                 n->id  = std::move(id);
-                assert (n->id.index() == type_id_node::decltype_);
+                assert (n->id.index() == type_id_node::postfix);
             }
             else
             {
-                error("'decltype' must be followed by a single parenthesized expression", false, c.position());
+                error("'" + std::string{c} + "' must be followed by a single parenthesized expression", false, c.position());
                 return {};
             }
         }
diff --git a/source/to_cpp1.h b/source/to_cpp1.h
index d4494d93a8..15c35c516c 100644
--- a/source/to_cpp1.h
+++ b/source/to_cpp1.h
@@ -1939,7 +1939,7 @@ class cppfront
             printer.print_cpp2("auto", pos);
         }
         else {
-            try_emit<type_id_node::decltype_  >(n.id);
+            try_emit<type_id_node::postfix    >(n.id);
             try_emit<type_id_node::unqualified>(n.id, 0, false);
             try_emit<type_id_node::qualified  >(n.id);
             try_emit<type_id_node::keyword    >(n.id);