Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Convert.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -283,5 +283,5 @@
 		decl->parent = get<AggregateDecl>().accept1( node->parent );
 		declPostamble( decl, node );
-		return nullptr; // ??
+		return nullptr;
 	}
 
@@ -321,8 +321,22 @@
 			get<Type>().accept1(node->base)
 		);
-		decl->data_constructors = get<StructDecl>().acceptL( node->data_constructors );
-		decl->data_union = get<UnionDecl>().accept1( node->data_union );
-		decl->tags = get<EnumDecl>().accept1( node->tag );
-		decl->tag_union = get<StructDecl>().accept1( node->tag_union );
+		// decl->data_constructors = get<StructDecl>().acceptL( node->data_constructors );
+		// decl->data_union = get<UnionDecl>().accept1( node->data_union );
+		// decl->tag = get<EnumDecl>().accept1( node->tag );
+		// decl->tag_union = get<StructDecl>().accept1( node->tag_union );
+		return aggregatePostamble( decl, node );
+	}
+
+	const ast::Decl * visit( const ast::AdtDecl * node ) override final {
+		if ( inCache(node) ) return nullptr;
+		auto decl = new AdtDecl(
+			node->name,
+			get<Attribute>().acceptL( node->attributes ),
+			LinkageSpec::Spec( node->linkage.val ),
+			get<StructDecl>().acceptL( node->data_constructors ),
+			get<UnionDecl>().accept1( node->data_union ),
+			get<EnumDecl>().accept1( node->tag ),
+			get<StructDecl>().accept1( node->tag_union )
+		);
 		return aggregatePostamble( decl, node );
 	}
@@ -1782,4 +1796,27 @@
 	}
 
+	virtual void visit( const AdtDecl * old ) override final {
+		if ( inCache( old ) ) return;
+		auto decl = new ast::AdtDecl(
+			old->location,
+			old->name,
+			GET_ACCEPT_V(attributes, Attribute),
+			{ old->linkage.val }
+		);
+		cache.emplace( old, decl );
+		decl->parent = GET_ACCEPT_1(parent, AggregateDecl);
+		decl->body = old->body;
+		decl->params = GET_ACCEPT_V(parameters, TypeDecl);
+		decl->members = GET_ACCEPT_V(members, Decl);
+		decl->extension = old->extension;
+		decl->uniqueId = old->uniqueId;
+		decl->storage = { old->storageClasses.val };
+		decl->data_constructors = GET_ACCEPT_V( data_constructors, StructDecl );
+		decl->data_union = GET_ACCEPT_1( data_union, UnionDecl );
+		decl->tag = GET_ACCEPT_1( tag, EnumDecl );
+		decl->tag_union = GET_ACCEPT_1( tag_union, StructDecl );
+		this->node = decl;
+	}
+
 	virtual void visit( const TraitDecl * old ) override final {
 		if ( inCache( old ) ) return;
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Decl.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -132,5 +132,5 @@
 
 // These must harmonize with the corresponding AggregateDecl::Aggregate enumerations.
-static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName", "data" };
+static const char * aggregateNames[] = { "struct", "union", "enum", "exception", "trait", "generator", "coroutine", "monitor", "thread", "NoAggregateName", "adt" };
 
 const char * AggregateDecl::aggrString( AggregateDecl::Aggregate aggr ) {
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Decl.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -248,5 +248,5 @@
 class AggregateDecl : public Decl {
 public:
-	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate, ADT };
+	enum Aggregate { Struct, Union, Enum, Exception, Trait, Generator, Coroutine, Monitor, Thread, NoAggregate, Adt };
 	static const char * aggrString( Aggregate aggr );
 
@@ -286,5 +286,5 @@
 	bool is_monitor  () const { return kind == Monitor  ; }
 	bool is_thread   () const { return kind == Thread   ; }
-	bool is_adt		 () const { return kind == ADT		; }
+	bool is_adt		 () const { return kind == Adt		; }
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -320,10 +320,4 @@
 	ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
 	enum class EnumHiding { Visible, Hide } hide;
-
-	std::vector<ptr<StructDecl>> data_constructors;
-	bool isData = false;
-	ptr<UnionDecl> data_union;
-	ptr<EnumDecl> tag;
-	ptr<StructDecl> tag_union;
 
 	EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false,
@@ -350,4 +344,24 @@
 };
 
+class AdtDecl final : public AggregateDecl {
+public:
+	std::vector<ptr<StructDecl>> data_constructors; // Todo: members?
+	ptr<UnionDecl> data_union;
+	ptr<EnumDecl> tag;
+	ptr<StructDecl> tag_union;
+
+	AdtDecl( const CodeLocation& loc, const std::string& name, 
+		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall )
+	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
+
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+
+	const char * typeString() const override { return aggrString( Adt ); }
+
+private:
+	AdtDecl * clone() const override { return new AdtDecl{ *this }; }
+	MUTATE_FRIEND
+};
+
 /// trait declaration `trait Foo( ... ) { ... };`
 class TraitDecl final : public AggregateDecl {
@@ -358,5 +372,4 @@
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-
 	const char * typeString() const override { return "trait"; }
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Fwd.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -32,4 +32,5 @@
 class UnionDecl;
 class EnumDecl;
+class AdtDecl;
 class TraitDecl;
 class NamedTypeDecl;
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Node.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -128,4 +128,6 @@
 template class ast::ptr_base< ast::EnumDecl, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::EnumDecl, ast::Node::ref_type::strong >;
+template class ast::ptr_base< ast::AdtDecl, ast::Node::ref_type::weak >; 
+template class ast::ptr_base< ast::AdtDecl, ast::Node::ref_type::strong >; 
 template class ast::ptr_base< ast::TraitDecl, ast::Node::ref_type::weak >;
 template class ast::ptr_base< ast::TraitDecl, ast::Node::ref_type::strong >;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Pass.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -139,4 +139,5 @@
 	const ast::Decl *             visit( const ast::UnionDecl            * ) override final;
 	const ast::Decl *             visit( const ast::EnumDecl             * ) override final;
+	const ast::Decl *			  visit( const ast::AdtDecl				 * ) override final;
 	const ast::Decl *             visit( const ast::TraitDecl            * ) override final;
 	const ast::Decl *             visit( const ast::TypeDecl             * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Pass.impl.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -693,8 +693,9 @@
 			maybe_accept( node, &EnumDecl::members    );
 			maybe_accept( node, &EnumDecl::attributes );
-			maybe_accept( node, &EnumDecl::data_constructors );
-			maybe_accept( node, &EnumDecl::data_union );
-			maybe_accept( node, &EnumDecl::tag );
-			maybe_accept( node, &EnumDecl::tag_union );
+
+			// maybe_accept( node, &EnumDecl::data_constructors );
+			// maybe_accept( node, &EnumDecl::data_union );
+			// maybe_accept( node, &EnumDecl::tag );
+			// maybe_accept( node, &EnumDecl::tag_union );
 		} else {
 			maybe_accept( node, &EnumDecl::base );
@@ -702,9 +703,31 @@
 			maybe_accept( node, &EnumDecl::members    );
 			maybe_accept( node, &EnumDecl::attributes );
-			maybe_accept( node, &EnumDecl::data_constructors );
-			maybe_accept( node, &EnumDecl::data_union );
-			maybe_accept( node, &EnumDecl::tag );
-			maybe_accept( node, &EnumDecl::tag_union );
-		}
+
+			// maybe_accept( node, &EnumDecl::data_constructors );
+			// maybe_accept( node, &EnumDecl::data_union );
+			// maybe_accept( node, &EnumDecl::tag );
+			// maybe_accept( node, &EnumDecl::tag_union );
+		}
+	}
+
+	VISIT_END( Decl, node );
+}
+
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::AdtDecl * node ) {
+	VISIT_START( node );
+
+	__pass::symtab::addAdt( core, 0, node );
+
+	if ( __visit_children() ) {
+		guard_symtab guard { *this };
+		maybe_accept( node, &AdtDecl::params );
+		maybe_accept( node, &AdtDecl::members );
+		maybe_accept( node, &AdtDecl::attributes );
+
+		maybe_accept( node, &AdtDecl::data_constructors );
+		maybe_accept( node, &AdtDecl::data_union );
+		maybe_accept( node, &AdtDecl::tag );
+		maybe_accept( node, &AdtDecl::tag_union );
 	}
 
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Pass.proto.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -399,4 +399,5 @@
 	SYMTAB_FUNC1( addStruct , const StructDecl *    );
 	SYMTAB_FUNC1( addEnum   , const EnumDecl *      );
+	SYMTAB_FUNC1( addAdt	, const AdtDecl *	    );
 	SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
 	SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Print.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -407,4 +407,9 @@
 
 	virtual const ast::Decl * visit( const ast::EnumDecl * node ) override final {
+		print(node);
+		return node;
+	}
+
+	virtual const ast::Decl * visit( const ast::AdtDecl * node ) override final {
 		print(node);
 		return node;
Index: src/AST/SymbolTable.cpp
===================================================================
--- src/AST/SymbolTable.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/SymbolTable.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -358,4 +358,24 @@
 }
 
+void SymbolTable::addAdt( const AdtDecl *decl ) {
+	++*stats().add_calls;
+	const std::string &id = decl->name;
+
+	if ( ! adtTable ) {
+		adtTable = AdtTable::new_ptr();
+	} else {
+		++*stats().map_lookups;
+		auto existing = adtTable->find( id );
+		if ( existing != adtTable->end()
+			&& existing->second.scope == scope
+			&& addedDeclConflicts( existing->second.decl, decl ) ) return;
+	
+	}
+
+	lazyInitScope();
+	++*stats().map_mutations;
+	adtTable = adtTable->set( id, scoped<AdtDecl>{ decl, scope });
+}
+
 void SymbolTable::addUnion( const std::string &id ) {
 	addUnion( new UnionDecl( CodeLocation(), id ) );
Index: src/AST/SymbolTable.hpp
===================================================================
--- src/AST/SymbolTable.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/SymbolTable.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -72,4 +72,5 @@
 	using StructTable = PersistentMap< std::string, scoped<StructDecl> >;
 	using EnumTable = PersistentMap< std::string, scoped<EnumDecl> >;
+	using AdtTable = PersistentMap< std::string, scoped<AdtDecl> >;
 	using UnionTable = PersistentMap< std::string, scoped<UnionDecl> >;
 	using TraitTable = PersistentMap< std::string, scoped<TraitDecl> >;
@@ -80,4 +81,5 @@
 	EnumTable::Ptr enumTable;      ///< enum namespace
 	UnionTable::Ptr unionTable;    ///< union namespace
+	AdtTable::Ptr adtTable;		   ///< adt namespace
 	TraitTable::Ptr traitTable;    ///< trait namespace
 	IdTable::Ptr specialFunctionTable[NUMBER_OF_KINDS];
@@ -138,4 +140,6 @@
 	/// Adds an enum declaration to the symbol table
 	void addEnum( const EnumDecl * decl );
+	/// Adds an adt declaration to the symbol table
+	void addAdt( const AdtDecl * decl );
 	/// Adds a union declaration to the symbol table by name
 	void addUnion( const std::string & id );
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/AST/Visitor.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -27,4 +27,5 @@
     virtual const ast::Decl *             visit( const ast::UnionDecl            * ) = 0;
     virtual const ast::Decl *             visit( const ast::EnumDecl             * ) = 0;
+    virtual const ast::Decl *             visit( const ast::AdtDecl              * ) = 0;
     virtual const ast::Decl *             visit( const ast::TraitDecl            * ) = 0;
     virtual const ast::Decl *             visit( const ast::TypeDecl             * ) = 0;
