diff --git a/base/schema-cplusplus/test/inputs/schema/mutually-recursive.schema/default/quicktype.hpp b/head/schema-cplusplus/test/inputs/schema/mutually-recursive.schema/default/quicktype.hpp
index 69da8b8..6a56492 100644
--- a/base/schema-cplusplus/test/inputs/schema/mutually-recursive.schema/default/quicktype.hpp
+++ b/head/schema-cplusplus/test/inputs/schema/mutually-recursive.schema/default/quicktype.hpp
@@ -89,11 +89,17 @@ namespace quicktype {
     }
     #endif
 
+    struct Foo;
+
     class Bar;
 
     class TopLevel;
 
-    using Foo = std::variant<std::vector<TopLevel>, std::shared_ptr<TopLevel>>;
+    struct Foo : std::variant<std::vector<TopLevel>, std::shared_ptr<TopLevel>> {
+        using base = std::variant<std::vector<TopLevel>, std::shared_ptr<TopLevel>>;
+        using base::base;
+        using base::operator=;
+    };
 
     class Bar {
         public:
@@ -130,6 +136,9 @@ void to_json(json & j, const Bar & x);
 
 void from_json(const json & j, TopLevel & x);
 void to_json(json & j, const TopLevel & x);
+
+void from_json(const json & j, Foo & x);
+void to_json(json & j, const Foo & x);
 }
 namespace nlohmann {
 template <>
@@ -156,6 +165,14 @@ namespace quicktype {
         j = json::object();
         j["bar"] = x.get_bar();
     }
+
+    inline void from_json(const json & j, Foo & x) {
+        x = j.get<Foo::base>();
+    }
+
+    inline void to_json(json & j, const Foo & x) {
+        j = static_cast<const Foo::base &>(x);
+    }
 }
 namespace nlohmann {
     inline void adl_serializer<std::variant<std::vector<quicktype::TopLevel>, std::shared_ptr<quicktype::TopLevel>>>::from_json(const json & j, std::variant<std::vector<quicktype::TopLevel>, std::shared_ptr<quicktype::TopLevel>> & x) {
diff --git a/head/schema-cplusplus/test/inputs/schema/recursive-union-flattening.schema/default/quicktype.hpp b/head/schema-cplusplus/test/inputs/schema/recursive-union-flattening.schema/default/quicktype.hpp
new file mode 100644
index 0000000..0ccdd29
--- /dev/null
+++ b/head/schema-cplusplus/test/inputs/schema/recursive-union-flattening.schema/default/quicktype.hpp
@@ -0,0 +1,373 @@
+//  To parse this JSON data, first install
+//
+//      json.hpp  https://github.com/nlohmann/json
+//
+//  Then include this file, and then do
+//
+//     TopLevel data = nlohmann::json::parse(jsonString);
+
+#pragma once
+
+#include <optional>
+#include <variant>
+#include "json.hpp"
+
+#include <optional>
+#include <stdexcept>
+#include <regex>
+
+#ifndef NLOHMANN_OPT_HELPER
+#define NLOHMANN_OPT_HELPER
+namespace nlohmann {
+    template <typename T>
+    struct adl_serializer<std::shared_ptr<T>> {
+        static void to_json(json & j, const std::shared_ptr<T> & opt) {
+            if (!opt) j = nullptr; else j = *opt;
+        }
+
+        static std::shared_ptr<T> from_json(const json & j) {
+            if (j.is_null()) return std::shared_ptr<T>(); else return std::make_shared<T>(j.get<T>());
+        }
+    };
+    template <typename T>
+    struct adl_serializer<std::optional<T>> {
+        static void to_json(json & j, const std::optional<T> & opt) {
+            if (!opt) j = nullptr; else j = *opt;
+        }
+
+        static std::optional<T> from_json(const json & j) {
+            if (j.is_null()) return std::optional<T>(); else return std::make_optional<T>(j.get<T>());
+        }
+    };
+}
+#endif
+
+namespace quicktype {
+    using nlohmann::json;
+
+    #ifndef NLOHMANN_UNTYPED_quicktype_HELPER
+    #define NLOHMANN_UNTYPED_quicktype_HELPER
+    inline json get_untyped(const json & j, const char * property) {
+        if (j.find(property) != j.end()) {
+            return j.at(property).get<json>();
+        }
+        return json();
+    }
+
+    inline json get_untyped(const json & j, std::string property) {
+        return get_untyped(j, property.data());
+    }
+    #endif
+
+    #ifndef NLOHMANN_OPTIONAL_quicktype_HELPER
+    #define NLOHMANN_OPTIONAL_quicktype_HELPER
+    template <typename T>
+    inline std::shared_ptr<T> get_heap_optional(const json & j, const char * property) {
+        auto it = j.find(property);
+        if (it != j.end() && !it->is_null()) {
+            return j.at(property).get<std::shared_ptr<T>>();
+        }
+        return std::shared_ptr<T>();
+    }
+
+    template <typename T>
+    inline std::shared_ptr<T> get_heap_optional(const json & j, std::string property) {
+        return get_heap_optional<T>(j, property.data());
+    }
+    template <typename T>
+    inline std::optional<T> get_stack_optional(const json & j, const char * property) {
+        auto it = j.find(property);
+        if (it != j.end() && !it->is_null()) {
+            return j.at(property).get<std::optional<T>>();
+        }
+        return std::optional<T>();
+    }
+
+    template <typename T>
+    inline std::optional<T> get_stack_optional(const json & j, std::string property) {
+        return get_stack_optional<T>(j, property.data());
+    }
+    #endif
+
+    struct X;
+    struct XElement;
+
+    class XClass;
+
+    struct X : std::shared_ptr<std::variant<std::vector<XElement>, bool, double, int64_t, std::map<std::string, nlohmann::json>, std::string>> {
+        using base = std::shared_ptr<std::variant<std::vector<XElement>, bool, double, int64_t, std::map<std::string, nlohmann::json>, std::string>>;
+        using base::base;
+        using base::operator=;
+    };
+
+    struct XElement : std::optional<std::variant<std::vector<nlohmann::json>, bool, std::shared_ptr<XClass>, double, int64_t, std::string>> {
+        using base = std::optional<std::variant<std::vector<nlohmann::json>, bool, std::shared_ptr<XClass>, double, int64_t, std::string>>;
+        using base::base;
+        using base::operator=;
+    };
+
+    class XClass {
+        public:
+        XClass() = default;
+        virtual ~XClass() = default;
+
+        private:
+        X x;
+
+        public:
+        X get_x() const { return x; }
+        void set_x(X value) { this->x = value; }
+    };
+
+    class TopLevelClass {
+        public:
+        TopLevelClass() = default;
+        virtual ~TopLevelClass() = default;
+
+        private:
+        X x;
+
+        public:
+        X get_x() const { return x; }
+        void set_x(X value) { this->x = value; }
+    };
+
+    using TopLevelElement = std::optional<std::variant<std::vector<nlohmann::json>, bool, TopLevelClass, double, int64_t, std::string>>;
+
+    using TopLevel = std::optional<std::variant<std::vector<TopLevelElement>, bool, double, int64_t, std::map<std::string, nlohmann::json>, std::string>>;
+}
+
+namespace quicktype {
+void from_json(const json & j, XClass & x);
+void to_json(json & j, const XClass & x);
+
+void from_json(const json & j, TopLevelClass & x);
+void to_json(json & j, const TopLevelClass & x);
+
+void from_json(const json & j, X & x);
+void to_json(json & j, const X & x);
+
+void from_json(const json & j, XElement & x);
+void to_json(json & j, const XElement & x);
+}
+namespace nlohmann {
+template <>
+struct adl_serializer<std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string>> {
+    static void from_json(const json & j, std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x);
+    static void to_json(json & j, const std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x);
+};
+
+template <>
+struct adl_serializer<std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string>> {
+    static void from_json(const json & j, std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string> & x);
+    static void to_json(json & j, const std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string> & x);
+};
+
+template <>
+struct adl_serializer<std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string>> {
+    static void from_json(const json & j, std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string> & x);
+    static void to_json(json & j, const std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string> & x);
+};
+
+template <>
+struct adl_serializer<std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string>> {
+    static void from_json(const json & j, std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x);
+    static void to_json(json & j, const std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x);
+};
+}
+namespace quicktype {
+    inline void from_json(const json & j, XClass& x) {
+        x.set_x(j.find("x") != j.end() ? j.at("x").get<X>() : X());
+    }
+
+    inline void to_json(json & j, const XClass & x) {
+        j = json::object();
+        j["x"] = x.get_x();
+    }
+
+    inline void from_json(const json & j, TopLevelClass& x) {
+        x.set_x(j.find("x") != j.end() ? j.at("x").get<X>() : X());
+    }
+
+    inline void to_json(json & j, const TopLevelClass & x) {
+        j = json::object();
+        j["x"] = x.get_x();
+    }
+
+    inline void from_json(const json & j, X & x) {
+        x = j.get<X::base>();
+    }
+
+    inline void to_json(json & j, const X & x) {
+        j = static_cast<const X::base &>(x);
+    }
+
+    inline void from_json(const json & j, XElement & x) {
+        x = j.get<XElement::base>();
+    }
+
+    inline void to_json(json & j, const XElement & x) {
+        j = static_cast<const XElement::base &>(x);
+    }
+}
+namespace nlohmann {
+    inline void adl_serializer<std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string>>::from_json(const json & j, std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x) {
+        if (j.is_boolean())
+            x = j.get<bool>();
+        else if (j.is_number_integer())
+            x = j.get<int64_t>();
+        else if (j.is_number())
+            x = j.get<double>();
+        else if (j.is_string())
+            x = j.get<std::string>();
+        else if (j.is_object())
+            x = j.get<std::map<std::string, json>>();
+        else if (j.is_array())
+            x = j.get<std::vector<quicktype::XElement>>();
+        else throw std::runtime_error("Could not deserialise!");
+    }
+
+    inline void adl_serializer<std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string>>::to_json(json & j, const std::variant<std::vector<quicktype::XElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x) {
+        switch (x.index()) {
+            case 0:
+                j = std::get<std::vector<quicktype::XElement>>(x);
+                break;
+            case 1:
+                j = std::get<bool>(x);
+                break;
+            case 2:
+                j = std::get<double>(x);
+                break;
+            case 3:
+                j = std::get<int64_t>(x);
+                break;
+            case 4:
+                j = std::get<std::map<std::string, json>>(x);
+                break;
+            case 5:
+                j = std::get<std::string>(x);
+                break;
+            default: throw std::runtime_error("Input JSON does not conform to schema!");
+        }
+    }
+
+    inline void adl_serializer<std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string>>::from_json(const json & j, std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string> & x) {
+        if (j.is_boolean())
+            x = j.get<bool>();
+        else if (j.is_number_integer())
+            x = j.get<int64_t>();
+        else if (j.is_number())
+            x = j.get<double>();
+        else if (j.is_string())
+            x = j.get<std::string>();
+        else if (j.is_object())
+            x = j.get<std::shared_ptr<quicktype::XClass>>();
+        else if (j.is_array())
+            x = j.get<std::vector<json>>();
+        else throw std::runtime_error("Could not deserialise!");
+    }
+
+    inline void adl_serializer<std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string>>::to_json(json & j, const std::variant<std::vector<json>, bool, std::shared_ptr<quicktype::XClass>, double, int64_t, std::string> & x) {
+        switch (x.index()) {
+            case 0:
+                j = std::get<std::vector<json>>(x);
+                break;
+            case 1:
+                j = std::get<bool>(x);
+                break;
+            case 2:
+                j = std::get<std::shared_ptr<quicktype::XClass>>(x);
+                break;
+            case 3:
+                j = std::get<double>(x);
+                break;
+            case 4:
+                j = std::get<int64_t>(x);
+                break;
+            case 5:
+                j = std::get<std::string>(x);
+                break;
+            default: throw std::runtime_error("Input JSON does not conform to schema!");
+        }
+    }
+
+    inline void adl_serializer<std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string>>::from_json(const json & j, std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string> & x) {
+        if (j.is_boolean())
+            x = j.get<bool>();
+        else if (j.is_number_integer())
+            x = j.get<int64_t>();
+        else if (j.is_number())
+            x = j.get<double>();
+        else if (j.is_string())
+            x = j.get<std::string>();
+        else if (j.is_object())
+            x = j.get<quicktype::TopLevelClass>();
+        else if (j.is_array())
+            x = j.get<std::vector<json>>();
+        else throw std::runtime_error("Could not deserialise!");
+    }
+
+    inline void adl_serializer<std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string>>::to_json(json & j, const std::variant<std::vector<json>, bool, quicktype::TopLevelClass, double, int64_t, std::string> & x) {
+        switch (x.index()) {
+            case 0:
+                j = std::get<std::vector<json>>(x);
+                break;
+            case 1:
+                j = std::get<bool>(x);
+                break;
+            case 2:
+                j = std::get<quicktype::TopLevelClass>(x);
+                break;
+            case 3:
+                j = std::get<double>(x);
+                break;
+            case 4:
+                j = std::get<int64_t>(x);
+                break;
+            case 5:
+                j = std::get<std::string>(x);
+                break;
+            default: throw std::runtime_error("Input JSON does not conform to schema!");
+        }
+    }
+
+    inline void adl_serializer<std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string>>::from_json(const json & j, std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x) {
+        if (j.is_boolean())
+            x = j.get<bool>();
+        else if (j.is_number_integer())
+            x = j.get<int64_t>();
+        else if (j.is_number())
+            x = j.get<double>();
+        else if (j.is_string())
+            x = j.get<std::string>();
+        else if (j.is_object())
+            x = j.get<std::map<std::string, json>>();
+        else if (j.is_array())
+            x = j.get<std::vector<quicktype::TopLevelElement>>();
+        else throw std::runtime_error("Could not deserialise!");
+    }
+
+    inline void adl_serializer<std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string>>::to_json(json & j, const std::variant<std::vector<quicktype::TopLevelElement>, bool, double, int64_t, std::map<std::string, json>, std::string> & x) {
+        switch (x.index()) {
+            case 0:
+                j = std::get<std::vector<quicktype::TopLevelElement>>(x);
+                break;
+            case 1:
+                j = std::get<bool>(x);
+                break;
+            case 2:
+                j = std::get<double>(x);
+                break;
+            case 3:
+                j = std::get<int64_t>(x);
+                break;
+            case 4:
+                j = std::get<std::map<std::string, json>>(x);
+                break;
+            case 5:
+                j = std::get<std::string>(x);
+                break;
+            default: throw std::runtime_error("Input JSON does not conform to schema!");
+        }
+    }
+}
diff --git a/base/schema-cplusplus/test/inputs/schema/rust-cycle-breaker-union.schema/default/quicktype.hpp b/head/schema-cplusplus/test/inputs/schema/rust-cycle-breaker-union.schema/default/quicktype.hpp
index 01ae820..7c41a99 100644
--- a/base/schema-cplusplus/test/inputs/schema/rust-cycle-breaker-union.schema/default/quicktype.hpp
+++ b/head/schema-cplusplus/test/inputs/schema/rust-cycle-breaker-union.schema/default/quicktype.hpp
@@ -89,9 +89,15 @@ namespace quicktype {
     }
     #endif
 
+    struct Next;
+
     class Node;
 
-    using Next = std::shared_ptr<std::variant<std::shared_ptr<Node>, std::string>>;
+    struct Next : std::shared_ptr<std::variant<std::shared_ptr<Node>, std::string>> {
+        using base = std::shared_ptr<std::variant<std::shared_ptr<Node>, std::string>>;
+        using base::base;
+        using base::operator=;
+    };
 
     class Node {
         public:
@@ -136,6 +142,9 @@ void to_json(json & j, const Node & x);
 
 void from_json(const json & j, TopLevel & x);
 void to_json(json & j, const TopLevel & x);
+
+void from_json(const json & j, Next & x);
+void to_json(json & j, const Next & x);
 }
 namespace nlohmann {
 template <>
@@ -146,7 +155,7 @@ struct adl_serializer<std::variant<std::shared_ptr<quicktype::Node>, std::string
 }
 namespace quicktype {
     inline void from_json(const json & j, Node& x) {
-        x.set_next(get_heap_optional<std::variant<std::shared_ptr<Node>, std::string>>(j, "next"));
+        x.set_next(j.find("next") != j.end() ? j.at("next").get<Next>() : Next());
         x.set_value(j.at("value").get<std::string>());
     }
 
@@ -157,7 +166,7 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, TopLevel& x) {
-        x.set_next(get_heap_optional<std::variant<std::shared_ptr<Node>, std::string>>(j, "next"));
+        x.set_next(j.find("next") != j.end() ? j.at("next").get<Next>() : Next());
         x.set_value(j.at("value").get<std::string>());
     }
 
@@ -166,6 +175,14 @@ namespace quicktype {
         j["next"] = x.get_next();
         j["value"] = x.get_value();
     }
+
+    inline void from_json(const json & j, Next & x) {
+        x = j.get<Next::base>();
+    }
+
+    inline void to_json(json & j, const Next & x) {
+        j = static_cast<const Next::base &>(x);
+    }
 }
 namespace nlohmann {
     inline void adl_serializer<std::variant<std::shared_ptr<quicktype::Node>, std::string>>::from_json(const json & j, std::variant<std::shared_ptr<quicktype::Node>, std::string> & x) {
diff --git a/base/schema-cplusplus/test/inputs/schema/union-list.schema/default/quicktype.hpp b/head/schema-cplusplus/test/inputs/schema/union-list.schema/default/quicktype.hpp
index 584d4b0..eadb167 100644
--- a/base/schema-cplusplus/test/inputs/schema/union-list.schema/default/quicktype.hpp
+++ b/head/schema-cplusplus/test/inputs/schema/union-list.schema/default/quicktype.hpp
@@ -88,9 +88,15 @@ namespace quicktype {
     }
     #endif
 
+    struct UnionList;
+
     class UnionListClass;
 
-    using UnionList = std::variant<std::shared_ptr<UnionListClass>, double>;
+    struct UnionList : std::variant<std::shared_ptr<UnionListClass>, double> {
+        using base = std::variant<std::shared_ptr<UnionListClass>, double>;
+        using base::base;
+        using base::operator=;
+    };
 
     class UnionListClass {
         public:
@@ -127,6 +133,9 @@ void to_json(json & j, const UnionListClass & x);
 
 void from_json(const json & j, TopLevel & x);
 void to_json(json & j, const TopLevel & x);
+
+void from_json(const json & j, UnionList & x);
+void to_json(json & j, const UnionList & x);
 }
 namespace nlohmann {
 template <>
@@ -153,6 +162,14 @@ namespace quicktype {
         j = json::object();
         j["list"] = x.get_list();
     }
+
+    inline void from_json(const json & j, UnionList & x) {
+        x = j.get<UnionList::base>();
+    }
+
+    inline void to_json(json & j, const UnionList & x) {
+        j = static_cast<const UnionList::base &>(x);
+    }
 }
 namespace nlohmann {
     inline void adl_serializer<std::variant<std::shared_ptr<quicktype::UnionListClass>, double>>::from_json(const json & j, std::variant<std::shared_ptr<quicktype::UnionListClass>, double> & x) {
diff --git a/base/schema-cplusplus/test/inputs/schema/vega-lite.schema/default/quicktype.hpp b/head/schema-cplusplus/test/inputs/schema/vega-lite.schema/default/quicktype.hpp
index 8b7e3c8..25c4b4b 100644
--- a/base/schema-cplusplus/test/inputs/schema/vega-lite.schema/default/quicktype.hpp
+++ b/head/schema-cplusplus/test/inputs/schema/vega-lite.schema/default/quicktype.hpp
@@ -221,6 +221,9 @@ namespace quicktype {
     }
     #endif
 
+    struct SelectionOperand;
+    struct LogicalOperandPredicate;
+
     /**
      * Determines how size calculation should be performed, one of `"content"` or `"padding"`.
      * The default setting (`"content"`) interprets the width and height settings as the data
@@ -5039,7 +5042,11 @@ namespace quicktype {
 
     class Selection;
 
-    using SelectionOperand = std::variant<std::shared_ptr<Selection>, std::string>;
+    struct SelectionOperand : std::variant<std::shared_ptr<Selection>, std::string> {
+        using base = std::variant<std::shared_ptr<Selection>, std::string>;
+        using base::base;
+        using base::operator=;
+    };
 
     class Selection {
         public:
@@ -5204,7 +5211,11 @@ namespace quicktype {
 
     class Predicate;
 
-    using LogicalOperandPredicate = std::variant<std::shared_ptr<Predicate>, std::string>;
+    struct LogicalOperandPredicate : std::variant<std::shared_ptr<Predicate>, std::string> {
+        using base = std::variant<std::shared_ptr<Predicate>, std::string>;
+        using base::base;
+        using base::operator=;
+    };
 
     class Predicate {
         public:
@@ -9845,6 +9856,12 @@ void to_json(json & j, const ResolveMode & x);
 
 void from_json(const json & j, SelectionDefType & x);
 void to_json(json & j, const SelectionDefType & x);
+
+void from_json(const json & j, SelectionOperand & x);
+void to_json(json & j, const SelectionOperand & x);
+
+void from_json(const json & j, LogicalOperandPredicate & x);
+void to_json(json & j, const LogicalOperandPredicate & x);
 }
 namespace nlohmann {
 template <>
@@ -11078,7 +11095,7 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, Selection& x) {
-        x.set_selection_not(get_heap_optional<std::variant<std::shared_ptr<Selection>, std::string>>(j, "not"));
+        x.set_selection_not(get_heap_optional<SelectionOperand>(j, "not"));
         x.set_selection_and(get_stack_optional<std::vector<SelectionOperand>>(j, "and"));
         x.set_selection_or(get_stack_optional<std::vector<SelectionOperand>>(j, "or"));
     }
@@ -11118,7 +11135,7 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, Predicate& x) {
-        x.set_predicate_not(get_heap_optional<std::variant<std::shared_ptr<Predicate>, std::string>>(j, "not"));
+        x.set_predicate_not(get_heap_optional<LogicalOperandPredicate>(j, "not"));
         x.set_predicate_and(get_stack_optional<std::vector<LogicalOperandPredicate>>(j, "and"));
         x.set_predicate_or(get_stack_optional<std::vector<LogicalOperandPredicate>>(j, "or"));
         x.set_equal(get_stack_optional<std::variant<bool, DateTime, double, std::string>>(j, "equal"));
@@ -11126,7 +11143,7 @@ namespace quicktype {
         x.set_time_unit(get_stack_optional<TimeUnit>(j, "timeUnit"));
         x.set_range(get_stack_optional<std::vector<RangeElement>>(j, "range"));
         x.set_one_of(get_stack_optional<std::vector<Equal>>(j, "oneOf"));
-        x.set_selection(get_heap_optional<std::variant<std::shared_ptr<Selection>, std::string>>(j, "selection"));
+        x.set_selection(get_heap_optional<SelectionOperand>(j, "selection"));
     }
 
     inline void to_json(json & j, const Predicate & x) {
@@ -11143,9 +11160,9 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, ConditionalValueDef& x) {
-        x.set_test(get_heap_optional<std::variant<std::shared_ptr<Predicate>, std::string>>(j, "test"));
+        x.set_test(get_heap_optional<LogicalOperandPredicate>(j, "test"));
         x.set_value(j.at("value").get<ConditionalValueDefValue>());
-        x.set_selection(get_heap_optional<std::variant<std::shared_ptr<Selection>, std::string>>(j, "selection"));
+        x.set_selection(get_heap_optional<SelectionOperand>(j, "selection"));
     }
 
     inline void to_json(json & j, const ConditionalValueDef & x) {
@@ -11288,9 +11305,9 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, ConditionalPredicateMarkPropFieldDefClass& x) {
-        x.set_test(get_heap_optional<std::variant<std::shared_ptr<Predicate>, std::string>>(j, "test"));
+        x.set_test(get_heap_optional<LogicalOperandPredicate>(j, "test"));
         x.set_value(get_stack_optional<std::variant<bool, double, std::string>>(j, "value"));
-        x.set_selection(get_heap_optional<std::variant<std::shared_ptr<Selection>, std::string>>(j, "selection"));
+        x.set_selection(get_heap_optional<SelectionOperand>(j, "selection"));
         x.set_aggregate(get_stack_optional<AggregateOp>(j, "aggregate"));
         x.set_bin(get_stack_optional<std::variant<bool, BinParams>>(j, "bin"));
         x.set_field(get_stack_optional<std::variant<RepeatRef, std::string>>(j, "field"));
@@ -11395,9 +11412,9 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, ConditionalPredicateFieldDefClass& x) {
-        x.set_test(get_heap_optional<std::variant<std::shared_ptr<Predicate>, std::string>>(j, "test"));
+        x.set_test(get_heap_optional<LogicalOperandPredicate>(j, "test"));
         x.set_value(get_stack_optional<std::variant<bool, double, std::string>>(j, "value"));
-        x.set_selection(get_heap_optional<std::variant<std::shared_ptr<Selection>, std::string>>(j, "selection"));
+        x.set_selection(get_heap_optional<SelectionOperand>(j, "selection"));
         x.set_aggregate(get_stack_optional<AggregateOp>(j, "aggregate"));
         x.set_bin(get_stack_optional<std::variant<bool, BinParams>>(j, "bin"));
         x.set_field(get_stack_optional<std::variant<RepeatRef, std::string>>(j, "field"));
@@ -11458,9 +11475,9 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, ConditionalPredicateTextFieldDefClass& x) {
-        x.set_test(get_heap_optional<std::variant<std::shared_ptr<Predicate>, std::string>>(j, "test"));
+        x.set_test(get_heap_optional<LogicalOperandPredicate>(j, "test"));
         x.set_value(get_stack_optional<std::variant<bool, double, std::string>>(j, "value"));
-        x.set_selection(get_heap_optional<std::variant<std::shared_ptr<Selection>, std::string>>(j, "selection"));
+        x.set_selection(get_heap_optional<SelectionOperand>(j, "selection"));
         x.set_aggregate(get_stack_optional<AggregateOp>(j, "aggregate"));
         x.set_bin(get_stack_optional<std::variant<bool, BinParams>>(j, "bin"));
         x.set_field(get_stack_optional<std::variant<RepeatRef, std::string>>(j, "field"));
@@ -11926,7 +11943,7 @@ namespace quicktype {
     }
 
     inline void from_json(const json & j, Transform& x) {
-        x.set_filter(get_heap_optional<std::variant<std::shared_ptr<Predicate>, std::string>>(j, "filter"));
+        x.set_filter(get_heap_optional<LogicalOperandPredicate>(j, "filter"));
         x.set_as(get_stack_optional<std::variant<std::vector<std::string>, std::string>>(j, "as"));
         x.set_calculate(get_stack_optional<std::string>(j, "calculate"));
         x.set_transform_default(get_stack_optional<std::string>(j, "default"));
@@ -12957,6 +12974,22 @@ namespace quicktype {
             default: throw std::runtime_error("Unexpected value in enumeration \"SelectionDefType\": " + std::to_string(static_cast<int>(x)));
         }
     }
+
+    inline void from_json(const json & j, SelectionOperand & x) {
+        x = j.get<SelectionOperand::base>();
+    }
+
+    inline void to_json(json & j, const SelectionOperand & x) {
+        j = static_cast<const SelectionOperand::base &>(x);
+    }
+
+    inline void from_json(const json & j, LogicalOperandPredicate & x) {
+        x = j.get<LogicalOperandPredicate::base>();
+    }
+
+    inline void to_json(json & j, const LogicalOperandPredicate & x) {
+        j = static_cast<const LogicalOperandPredicate::base &>(x);
+    }
 }
 namespace nlohmann {
     inline void adl_serializer<std::variant<quicktype::AutoSizeParams, quicktype::AutosizeType>>::from_json(const json & j, std::variant<quicktype::AutoSizeParams, quicktype::AutosizeType> & x) {
