diff --git a/src/json_export.cpp b/src/json_export.cpp
index 1baac478a..dbbb2b7e8 100644
--- a/src/json_export.cpp
+++ b/src/json_export.cpp
@@ -1,5 +1,11 @@
 #include "behaviortree_cpp/json_export.h"
 
+namespace
+{
+constexpr std::string_view kTypeField = "__type";
+constexpr std::string_view kValueField = "value";
+}  // namespace
+
 namespace BT
 {
 
@@ -16,19 +22,23 @@ bool JsonExporter::toJson(const Any& any, nlohmann::json& dst) const
 
   if(any.isString())
   {
-    dst = any.cast<std::string>();
+    dst[kTypeField] = "string";
+    dst[kValueField] = any.cast<std::string>();
   }
   else if(type == typeid(int64_t))
   {
-    dst = any.cast<int64_t>();
+    dst[kTypeField] = "int64_t";
+    dst[kValueField] = any.cast<int64_t>();
   }
   else if(type == typeid(uint64_t))
   {
-    dst = any.cast<uint64_t>();
+    dst[kTypeField] = "uint64_t";
+    dst[kValueField] = any.cast<uint64_t>();
   }
   else if(type == typeid(double))
   {
-    dst = any.cast<double>();
+    dst[kTypeField] = "double";
+    dst[kValueField] = any.cast<double>();
   }
   else
   {
@@ -51,33 +61,41 @@ JsonExporter::ExpectedEntry JsonExporter::fromJson(const nlohmann::json& source)
   {
     return nonstd::make_unexpected("json object is null");
   }
-  if(source.is_string())
-  {
-    return Entry{ BT::Any(source.get<std::string>()),
-                  BT::TypeInfo::Create<std::string>() };
-  }
-  if(source.is_number_unsigned())
-  {
-    return Entry{ BT::Any(source.get<uint64_t>()), BT::TypeInfo::Create<uint64_t>() };
-  }
-  if(source.is_number_integer())
+  if(!source.contains(kTypeField))
   {
-    return Entry{ BT::Any(source.get<int64_t>()), BT::TypeInfo::Create<int64_t>() };
-  }
-  if(source.is_number_float())
-  {
-    return Entry{ BT::Any(source.get<double>()), BT::TypeInfo::Create<double>() };
-  }
-  if(source.is_boolean())
-  {
-    return Entry{ BT::Any(source.get<bool>()), BT::TypeInfo::Create<bool>() };
+    return nonstd::make_unexpected("Missing field '" + std::string(kTypeField) + "'.");
   }
 
-  if(!source.contains("__type"))
+  const auto source_value_it = source.find(kValueField);
+  if(source_value_it != source.end())
   {
-    return nonstd::make_unexpected("Missing field '__type'");
+    if(source_value_it->is_string())
+    {
+      return Entry{ BT::Any(source_value_it->get<std::string>()),
+                    BT::TypeInfo::Create<std::string>() };
+    }
+    if(source_value_it->is_number_unsigned())
+    {
+      return Entry{ BT::Any(source_value_it->get<uint64_t>()),
+                    BT::TypeInfo::Create<uint64_t>() };
+    }
+    if(source_value_it->is_number_integer())
+    {
+      return Entry{ BT::Any(source_value_it->get<int64_t>()),
+                    BT::TypeInfo::Create<int64_t>() };
+    }
+    if(source_value_it->is_number_float())
+    {
+      return Entry{ BT::Any(source_value_it->get<double>()),
+                    BT::TypeInfo::Create<double>() };
+    }
+    if(source_value_it->is_boolean())
+    {
+      return Entry{ BT::Any(source_value_it->get<bool>()), BT::TypeInfo::Create<bool>() };
+    }
   }
-  auto type_it = type_names_.find(source["__type"]);
+
+  auto type_it = type_names_.find(source[kTypeField]);
   if(type_it == type_names_.end())
   {
     return nonstd::make_unexpected("Type not found in registered list");
diff --git a/tests/gtest_json.cpp b/tests/gtest_json.cpp
index f7b9e5909..752190c52 100644
--- a/tests/gtest_json.cpp
+++ b/tests/gtest_json.cpp
@@ -3,6 +3,12 @@
 #include "behaviortree_cpp/json_export.h"
 #include "behaviortree_cpp/basic_types.h"
 
+namespace
+{
+constexpr std::string_view kTypeField = "__type";
+constexpr std::string_view kValueField = "value";
+}  // namespace
+
 //----------- Custom types ----------
 
 namespace TestTypes
@@ -95,16 +101,27 @@ TEST_F(JsonTest, TwoWaysConversion)
   TestTypes::Pose3D pose = { { 1, 2, 3 }, { 4, 5, 6, 7 } };
 
   nlohmann::json json;
+  exporter.toJson(BT::Any("string_val"), json["string"]);
   exporter.toJson(BT::Any(69), json["int"]);
+  exporter.toJson(BT::Any(static_cast<uint64_t>(96)), json["uint"]);
   exporter.toJson(BT::Any(3.14), json["real"]);
   exporter.toJson(BT::Any(pose), json["pose"]);
 
   std::cout << json.dump(2) << std::endl;
 
-  ASSERT_EQ(json["int"], 69);
-  ASSERT_EQ(json["real"], 3.14);
+  ASSERT_EQ(json["string"][kTypeField], "string");
+  ASSERT_EQ(json["string"][kValueField], "string_val");
+
+  ASSERT_EQ(json["int"][kTypeField], "int64_t");
+  ASSERT_EQ(json["int"][kValueField], 69);
+
+  ASSERT_EQ(json["uint"][kTypeField], "uint64_t");
+  ASSERT_EQ(json["uint"][kValueField], 96);
+
+  ASSERT_EQ(json["real"][kTypeField], "double");
+  ASSERT_EQ(json["real"][kValueField], 3.14);
 
-  ASSERT_EQ(json["pose"]["__type"], "Pose3D");
+  ASSERT_EQ(json["pose"][kTypeField], "Pose3D");
   ASSERT_EQ(json["pose"]["pos"]["x"], 1);
   ASSERT_EQ(json["pose"]["pos"]["y"], 2);
   ASSERT_EQ(json["pose"]["pos"]["z"], 3);
@@ -126,8 +143,12 @@ TEST_F(JsonTest, TwoWaysConversion)
   ASSERT_EQ(pose.rot.y, pose2.rot.y);
   ASSERT_EQ(pose.rot.z, pose2.rot.z);
 
-  auto num = exporter.fromJson(json["int"])->first.cast<int>();
-  ASSERT_EQ(num, 69);
+  auto string_val = exporter.fromJson(json["string"])->first.cast<std::string>();
+  ASSERT_EQ(string_val, "string_val");
+  auto int_val = exporter.fromJson(json["int"])->first.cast<int>();
+  ASSERT_EQ(int_val, 69);
+  auto uint_val = exporter.fromJson(json["uint"])->first.cast<uint>();
+  ASSERT_EQ(uint_val, 96);
   auto real = exporter.fromJson(json["real"])->first.cast<double>();
   ASSERT_EQ(real, 3.14);
 }