diff --git a/spec/std/named_tuple_spec.cr b/spec/std/named_tuple_spec.cr
index 6dc6684be827..80e326fa253e 100644
--- a/spec/std/named_tuple_spec.cr
+++ b/spec/std/named_tuple_spec.cr
@@ -148,7 +148,7 @@ describe "NamedTuple" do
     typeof(val).should eq(Int32 | Char | Nil)
   end
 
-  describe "dig?" do
+  describe "#dig?" do
     it "gets the value at given path given splat" do
       h = {a: {b: {c: [10, 20]}}, x: {a: "b"}}
 
@@ -165,7 +165,7 @@ describe "NamedTuple" do
     end
   end
 
-  describe "dig" do
+  describe "#dig" do
     it "gets the value at given path given splat" do
       h = {a: {b: {c: [10, 20]}}, x: {a: "b", c: nil}}
 
@@ -290,9 +290,18 @@ describe "NamedTuple" do
     NamedTuple.new.empty?.should be_true
   end
 
-  it "does to_a" do
-    tup = {a: 1, b: 'a'}
-    tup.to_a.should eq([{:a, 1}, {:b, 'a'}])
+  describe "#to_a" do
+    it "creates an array of key-value pairs" do
+      tup = {a: 1, b: 'a'}
+      tup.to_a.should eq([{:a, 1}, {:b, 'a'}])
+    end
+
+    it "preserves key type for empty named tuples" do
+      tup = NamedTuple.new
+      arr = tup.to_a
+      arr.should be_empty
+      arr.should be_a(Array({Symbol, NoReturn}))
+    end
   end
 
   it "does map" do
@@ -327,10 +336,19 @@ describe "NamedTuple" do
     u.should_not eq(v)
   end
 
-  it "does to_h" do
-    tup1 = {a: 1, b: "hello"}
-    hash = tup1.to_h
-    hash.should eq({:a => 1, :b => "hello"})
+  describe "#to_h" do
+    it "creates a hash" do
+      tup1 = {a: 1, b: "hello"}
+      hash = tup1.to_h
+      hash.should eq({:a => 1, :b => "hello"})
+    end
+
+    it "creates an empty hash from an empty named tuple" do
+      tup = NamedTuple.new
+      hash = tup.to_h
+      hash.should be_empty
+      hash.should be_a(Hash(Symbol, NoReturn))
+    end
   end
 
   it "does to_s" do
diff --git a/src/named_tuple.cr b/src/named_tuple.cr
index 32d723e2ffd3..22a9a55e92a2 100644
--- a/src/named_tuple.cr
+++ b/src/named_tuple.cr
@@ -498,12 +498,18 @@ struct NamedTuple
   # tuple = {name: "Crystal", year: 2011}
   # tuple.to_a # => [{:name, "Crystal"}, {:year, 2011}]
   # ```
+  #
+  # NOTE: `to_a` on an empty named tuple produces an `Array(Tuple(Symbol, NoReturn))`
   def to_a
-    ary = Array({typeof(first_key_internal), typeof(first_value_internal)}).new(size)
-    each do |key, value|
-      ary << {key.as(typeof(first_key_internal)), value.as(typeof(first_value_internal))}
-    end
-    ary
+    {% if T.size == 0 %}
+      [] of {Symbol, NoReturn}
+    {% else %}
+      [
+        {% for key in T %}
+          { {{key.symbolize}}, self[{{key.symbolize}}] },
+        {% end %}
+      ]
+    {% end %}
   end
 
   # Returns a `Hash` with the keys and values in this named tuple.
@@ -512,9 +518,11 @@ struct NamedTuple
   # tuple = {name: "Crystal", year: 2011}
   # tuple.to_h # => {:name => "Crystal", :year => 2011}
   # ```
+  #
+  # NOTE: `to_h` on an empty named tuple produces a `Hash(Symbol, NoReturn)`
   def to_h
     {% if T.size == 0 %}
-      {} of NoReturn => NoReturn
+      {} of Symbol => NoReturn
     {% else %}
       {
         {% for key in T %}