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;
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/CodeGen/CodeGenerator.cc	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -296,19 +296,20 @@
 
 	void CodeGenerator::handleData( EnumDecl * dataDecl ) {
-		output << " /** data type */" << endl;
-		for ( StructDecl * decl : dataDecl->data_constructors ) {
-			postvisit(decl);
-			output << ";" << endl;
-		}
-		postvisit( dataDecl->data_union );
-		output << ";" << endl;
-		postvisit( dataDecl->tags );
-		output << ";" << endl;
-		postvisit( dataDecl->tag_union );
-		output << ";" << endl;
+		// output << " /** data type */" << endl;
+		// for ( StructDecl * decl : dataDecl->data_constructors ) {
+		// 	postvisit(decl);
+		// 	output << ";" << endl;
+		// }
+		// postvisit( dataDecl->data_union );
+		// output << ";" << endl;
+		// postvisit( dataDecl->tag );
+		// output << ";" << endl;
+		// postvisit( dataDecl->tag_union );
+		// output << ";" << endl;
+		assert(false);
 	}
 
 	void CodeGenerator::postvisit( EnumDecl * enumDecl ) {
-		if ( enumDecl->data_constructors.size() > 0 ) return handleData( enumDecl );
+		// if ( enumDecl->data_constructors.size() > 0 ) return handleData( enumDecl );
  		extension( enumDecl );
 		std::list< Declaration* > &memb = enumDecl->get_members();
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Common/CodeLocationTools.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -105,4 +105,5 @@
     macro(UnionDecl, Decl) \
     macro(EnumDecl, Decl) \
+	macro(AdtDecl, Decl) \
     macro(TraitDecl, Decl) \
     macro(TypeDecl, Decl) \
Index: src/Common/PassVisitor.h
===================================================================
--- src/Common/PassVisitor.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Common/PassVisitor.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -69,4 +69,6 @@
 	virtual void visit( EnumDecl * aggregateDecl ) override final;
 	virtual void visit( const EnumDecl * aggregateDecl ) override final;
+	virtual void visit( AdtDecl * aggregateDecl ) override final;
+	virtual void visit( const AdtDecl * AggregateDecl ) override final;
 	virtual void visit( TraitDecl * aggregateDecl ) override final;
 	virtual void visit( const TraitDecl * aggregateDecl ) override final;
@@ -269,4 +271,5 @@
 	virtual Declaration * mutate( UnionDecl * aggregateDecl ) override final;
 	virtual Declaration * mutate( EnumDecl * aggregateDecl ) override final;
+	virtual Declaration * mutate( AdtDecl * aggregateDecl ) override final;
 	virtual Declaration * mutate( TraitDecl * aggregateDecl ) override final;
 	virtual Declaration * mutate( TypeDecl * typeDecl ) override final;
@@ -439,4 +442,5 @@
 	void indexerAddStructFwd( const StructDecl          * node  ) { indexer_impl_addStructFwd( pass, 0, node ); }
 	void indexerAddEnum     ( const EnumDecl            * node  ) { indexer_impl_addEnum     ( pass, 0, node ); }
+	void indexerAddAdt		( const AdtDecl				* node  ) { indexer_impl_addAdt		 ( pass, 0, node ); }
 	void indexerAddUnion    ( const std::string         & id    ) { indexer_impl_addUnion    ( pass, 0, id   ); }
 	void indexerAddUnion    ( const UnionDecl           * node  ) { indexer_impl_addUnion    ( pass, 0, node ); }
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Common/PassVisitor.impl.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -754,7 +754,4 @@
 
 	// unlike structs, traits, and unions, enums inject their members into the global scope
-	maybeAccept_impl( node->data_constructors, *this );
-	maybeAccept_impl( node->data_union, *this );
-	maybeAccept_impl( node->tags, *this );
 	maybeAccept_impl( node->parameters, *this );
 	maybeAccept_impl( node->members   , *this );
@@ -785,4 +782,53 @@
 
 	// unlike structs, traits, and unions, enums inject their members into the global scope
+	maybeMutate_impl( node->parameters, *this );
+	maybeMutate_impl( node->members   , *this );
+	maybeMutate_impl( node->attributes, *this );
+
+	MUTATE_END( Declaration, node );
+}
+
+template< typename pass_type >
+void PassVisitor< pass_type >::visit( AdtDecl * node ) {
+	VISIT_START( node );
+
+	indexerAddAdt( node );
+
+	// unlike structs, traits, and unions, enums inject their members into the global scope
+	maybeAccept_impl( node->data_constructors, *this );
+	maybeAccept_impl( node->data_union, *this );
+	maybeAccept_impl( node->tag, *this );
+
+	maybeAccept_impl( node->parameters, *this );
+	maybeAccept_impl( node->members   , *this );
+	maybeAccept_impl( node->attributes, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+void PassVisitor< pass_type >::visit( const AdtDecl * node ) {
+	VISIT_START( node );
+
+	maybeAccept_impl( node->data_constructors, *this );
+	maybeAccept_impl( node->data_union, *this );
+	maybeAccept_impl( node->tag, *this );
+
+	maybeAccept_impl( node->parameters, *this );
+	maybeAccept_impl( node->members   , *this );
+	maybeAccept_impl( node->attributes, *this );
+
+
+	VISIT_END( node );
+}  
+
+template< typename pass_type >
+Declaration * PassVisitor< pass_type >::mutate( AdtDecl * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->data_constructors, *this );
+	maybeMutate_impl( node->data_union, *this );
+	maybeMutate_impl( node->tag, *this );
+
 	maybeMutate_impl( node->parameters, *this );
 	maybeMutate_impl( node->members   , *this );
Index: src/Common/PassVisitor.proto.h
===================================================================
--- src/Common/PassVisitor.proto.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Common/PassVisitor.proto.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -233,4 +233,5 @@
 INDEXER_FUNC1( addStruct , const StructDecl *                );
 INDEXER_FUNC1( addEnum   , const EnumDecl *                  );
+INDEXER_FUNC1( addAdt	 , const AdtDecl * 					 );
 INDEXER_FUNC1( addUnion  , const UnionDecl *                 );
 INDEXER_FUNC1( addTrait  , const TraitDecl *                 );
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Parser/DeclarationNode.cc	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -279,10 +279,12 @@
 } // DeclarationNode::newEnum
 
-DeclarationNode * DeclarationNode::newADT( const string * name, DeclarationNode * constructors ) {
-	DeclarationNode * newnode = newEnum( name, nullptr, true, false );
-	newnode->type->enumeration.isData = true;
-	newnode->type->enumeration.data_constructors = constructors;
-	return newnode;
-}
+DeclarationNode * DeclarationNode::newAdt( const string * name, DeclarationNode * constructors ) {
+	assert( name );
+	DeclarationNode * newnode = new DeclarationNode;
+	newnode->type = new TypeData( TypeData::Adt );
+	newnode->type->adt.name = name;
+	newnode->type->adt.data_constructors = constructors;
+	return newnode;
+} // DeclarationNode::newAdt
 
 
@@ -1098,5 +1100,6 @@
 }
 
-void buildDataConstructors( DeclarationNode * firstNode, std::vector<ast::ptr<ast::StructDecl>> & outputList ) {
+std::vector<ast::ptr<ast::StructDecl>> buildDataConstructors( DeclarationNode * firstNode ) {
+	std::vector<ast::ptr<ast::StructDecl>> outputList;
 	std::back_insert_iterator<std::vector<ast::ptr<ast::StructDecl>>> out( outputList );
 	for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
@@ -1124,8 +1127,9 @@
 		*out++ = ctor;		
 	}
-}
-
-ast::UnionDecl * buildDataUnion( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList ) {
-	ast::UnionDecl * out = new ast::UnionDecl( data->location, "temp_data_union" );
+	return outputList;
+}
+
+ast::UnionDecl * buildDataUnion( const CodeLocation & loc, const std::vector<ast::ptr<ast::StructDecl>> & typeList ) {
+	ast::UnionDecl * out = new ast::UnionDecl( loc, "temp_data_union" );
 	// size_t index = 0;
 	if ( typeList.size() > 0 ) out->set_body( true );
@@ -1145,6 +1149,6 @@
 }
 
-ast::EnumDecl * buildTag( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList ) {
-	ast::EnumDecl * out = new ast::EnumDecl( data->location, "temp_data_tag" );
+ast::EnumDecl * buildTag( const CodeLocation & loc, std::vector<ast::ptr<ast::StructDecl>> & typeList ) {
+	ast::EnumDecl * out = new ast::EnumDecl( loc, "temp_data_tag" );
 	if ( typeList.size() > 0 ) out->set_body( true );
 	for ( const ast::ptr<ast::StructDecl> structDecl : typeList ) {
@@ -1161,8 +1165,8 @@
 }
 
-ast::StructDecl * buildTaggedUnions( const ast::EnumDecl * data, const ast::EnumDecl * tags, const ast::UnionDecl * data_union ) {
+ast::StructDecl * buildTaggedUnions( const TypeData * data, const ast::EnumDecl * tags, const ast::UnionDecl * data_union ) {
 	assert( tags->members.size() == data_union->members.size() );
-	ast::StructDecl * out = new ast::StructDecl( data->location, data->name );
-	out->kind = ast::AggregateDecl::ADT;
+	ast::StructDecl * out = new ast::StructDecl( data->location, *(data->adt.name) );
+	out->kind = ast::AggregateDecl::Adt;
 
 	out->set_body( true );
Index: src/Parser/DeclarationNode.h
===================================================================
--- src/Parser/DeclarationNode.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Parser/DeclarationNode.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -77,5 +77,5 @@
 
 	// Experimental algebric data type
-	static DeclarationNode * newADT( const std::string * name, DeclarationNode * constructors );
+	static DeclarationNode * newAdt( const std::string * name, DeclarationNode * constructors );
 	static DeclarationNode * newDataConstructor( const std::string * name );
 	// static DeclarationNode * newDataConstructor( const std::string * name, DeclarationNode * typeSpecifiers );
@@ -216,8 +216,9 @@
 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
 void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
-void buildDataConstructors( DeclarationNode * firstNode, std::vector<ast::ptr<ast::StructDecl>> & outputList );
-ast::UnionDecl * buildDataUnion( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList );
-ast::EnumDecl * buildTag( ast::EnumDecl * data, const std::vector<ast::ptr<ast::StructDecl>> & typeList );
-ast::StructDecl * buildTaggedUnions( const ast::EnumDecl * data, const ast::EnumDecl * tags, const ast::UnionDecl * data_union );
+
+std::vector<ast::ptr<ast::StructDecl>> buildDataConstructors( DeclarationNode * firstNode );
+ast::UnionDecl * buildDataUnion( const CodeLocation & loc, const std::vector<ast::ptr<ast::StructDecl>> & typeList );
+ast::EnumDecl * buildTag( const CodeLocation & loc, std::vector<ast::ptr<ast::StructDecl>> & typeList );
+ast::StructDecl * buildTaggedUnions( const TypeData * data, const ast::EnumDecl * tag, const ast::UnionDecl * data_union );
 
 template<typename AstType, typename NodeType,
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Parser/TypeData.cc	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -59,4 +59,8 @@
 		enumeration.anon = false;
 		break;
+	case Adt:
+		adt.name = nullptr;
+		adt.data_constructors = nullptr;
+		break;
 	case Aggregate:
 		aggregate.kind = ast::AggregateDecl::NoAggregate;
@@ -160,4 +164,8 @@
 		delete qualified.child;
 		break;
+	case Adt:
+		delete adt.data_constructors;
+		delete adt.name;
+		break;
 	} // switch
 } // TypeData::~TypeData
@@ -217,4 +225,9 @@
 		newtype->enumeration.body = enumeration.body;
 		newtype->enumeration.anon = enumeration.anon;
+		newtype->enumeration.data_constructors = maybeClone( enumeration.data_constructors );
+		break;
+	case Adt:
+		newtype->adt.data_constructors = maybeClone( enumeration.data_constructors );
+		newtype->adt.name = new string ( *adt.name );
 		break;
 	case Symbolic:
@@ -459,4 +472,6 @@
 	case Enum:
 		return enumeration.name;
+	case Adt:
+		return adt.name;
 	case Symbolic:
 	case SymbolicInst:
@@ -822,4 +837,5 @@
 	case TypeData::Symbolic:
 	case TypeData::Enum:
+	case TypeData::Adt:
 	case TypeData::Aggregate:
 		assert( false );
@@ -1261,11 +1277,12 @@
 	buildList( td->enumeration.constants, ret->members );
 	if ( td->enumeration.data_constructors != nullptr ) {
-		buildDataConstructors( td->enumeration.data_constructors, ret->data_constructors );
-		ret->data_union = buildDataUnion( ret, ret->data_constructors );
-		ret->tag = buildTag( ret, ret->data_constructors );
-		ret->tag_union = buildTaggedUnions( ret, ret->tag.get(), ret->data_union.get() );
+		assert( false );
+		// ret->data_constructors = buildDataConstructors( td->enumeration.data_constructors );
+		// ret->data_union = buildDataUnion( td->location, ret->data_constructors );
+		// ret->tag = buildTag( td->location, ret->data_constructors );
+		// ret->tag_union = buildTaggedUnions( td, ret->tag.get(), ret->data_union.get() );
 	}
 
-	if ( ret->data_constructors.size() > 0 ) ret->isData = true;
+	// if ( ret->data_constructors.size() > 0 ) ret->isData = true;
 	auto members = ret->members.begin();
 	ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
@@ -1294,4 +1311,16 @@
 	return ret;
 } // buildEnum
+
+ast::AdtDecl * buildAdt(const TypeData * td,
+	std::vector<ast::ptr<ast::Attribute>> && attributes,
+	ast::Linkage::Spec linkage ) {
+	assert( td->kind == TypeData::Adt );
+	ast::AdtDecl * ret = new ast::AdtDecl( td->location, *(td->adt.name) );
+	ret->data_constructors = buildDataConstructors( td->adt.data_constructors );
+	ret->data_union = buildDataUnion( td->location, ret->data_constructors );
+	ret->tag = buildTag( td->location, ret->data_constructors );
+	ret->tag_union = buildTaggedUnions( td, ret->tag.get(), ret->data_union.get() );
+	return ret;
+}
 
 
@@ -1437,4 +1466,6 @@
 	} else if ( td->kind == TypeData::Enum ) {
 		return buildEnum( td, std::move( attributes ), linkage );
+	} else if ( td->kind == TypeData::Adt) {
+		return buildAdt( td, std::move( attributes), linkage );
 	} else if ( td->kind == TypeData::Symbolic ) {
 		return buildSymbolic( td, std::move( attributes ), name, scs, linkage );
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Parser/TypeData.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -25,5 +25,5 @@
 struct TypeData {
 	enum Kind { Basic, Pointer, Reference, Array, Function, Aggregate, AggregateInst, Enum, EnumConstant, Symbolic,
-				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, ADT, Ctor, Unknown };
+				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, Adt, Ctor, Unknown };
 
 	struct Aggregate_t {
@@ -65,10 +65,5 @@
 	struct ADT_t {
 		const std::string * name = nullptr;
-		DeclarationNode * constructors;
-	};
-
-	struct Constructor_t {
-		const std::string * name;
-		DeclarationNode * type; // types?
+		DeclarationNode * data_constructors;
 	};
 
@@ -112,5 +107,4 @@
 	Enumeration_t enumeration;
 	ADT_t adt;
-	Constructor_t data_constructor;
 
 	Function_t function;
@@ -140,4 +134,5 @@
 ast::TypeDecl * buildVariable( const TypeData * );
 ast::EnumDecl * buildEnum( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec );
+ast::EnumDecl * buildAst( const TypeData *, std::vector<ast::ptr<ast::Attribute>> &&, ast::Linkage::Spec );
 ast::TypeInstType * buildSymbolicInst( const TypeData * );
 ast::TupleType * buildTuple( const TypeData * );
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Parser/parser.yy	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -2702,5 +2702,5 @@
 	 '{' value_list '}'
 	 {
-		$$ = DeclarationNode::newADT( $2, $5 );
+		$$ = DeclarationNode::newAdt( $2, $5 );
 	 }
 	;
Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/SymTab/Indexer.cc	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -606,4 +606,24 @@
 	}
 
+	void Indexer::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 Indexer::addUnion( const std::string & id ) {
 		addUnion( new UnionDecl( id ) );
Index: src/SymTab/Indexer.h
===================================================================
--- src/SymTab/Indexer.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/SymTab/Indexer.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -89,4 +89,5 @@
 		void addStruct( const StructDecl * decl );
 		void addEnum( const EnumDecl * decl );
+		void addAdt( const AdtDecl * decl );
 		void addUnion( const std::string & id );
 		void addUnion( const UnionDecl * decl );
@@ -124,4 +125,5 @@
 		using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >;
 		using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >;
+		using AdtTable = PersistentMap< std::string, Scoped<AdtDecl> >;
 
 		IdTable::Ptr idTable;          ///< identifier namespace
@@ -131,4 +133,5 @@
 		UnionTable::Ptr unionTable;    ///< union namespace
 		TraitTable::Ptr traitTable;    ///< trait namespace
+		AdtTable::Ptr adtTable;		   ///< adt namespace
 
 		Ptr prevScope;                 ///< reference to indexer for parent scope
Index: src/SynTree/Declaration.h
===================================================================
--- src/SynTree/Declaration.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/SynTree/Declaration.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -342,9 +342,4 @@
 	enum EnumHiding { Visible, Hide } hide;
 
-	std::list<StructDecl*> data_constructors;
-	UnionDecl * data_union;
-	EnumDecl * tags;
-	StructDecl * tag_union;
-
 	EnumDecl( const std::string & name,
 	 const std::list< Attribute * > & attributes = std::list< class Attribute * >(),
@@ -367,4 +362,38 @@
 };
 
+class AdtDecl : public AggregateDecl {
+	typedef AggregateDecl Parent;
+  public:
+	std::list<StructDecl*> data_constructors;
+	UnionDecl * data_union;
+	EnumDecl * tag;
+	StructDecl * tag_union;
+
+	AdtDecl( const std::string & name,
+	 const std::list< Attribute * > & attributes = std::list< class Attribute * >(),
+	 LinkageSpec::Spec linkage = LinkageSpec::Cforall, 
+	 const std::list< StructDecl* > data_constructors = std::list< StructDecl * >(),
+	 UnionDecl * data_union = nullptr, EnumDecl * tag = nullptr, StructDecl * tag_union = nullptr )
+	 : Parent( name, attributes, linkage ), data_constructors(data_constructors), 
+	 data_union( data_union ), tag( tag ), tag_union( tag_union ) {}
+
+	AdtDecl( const AdtDecl & other )
+	 : Parent( other ) {}
+
+	virtual AdtDecl * clone() const override { return new AdtDecl( *this ); }
+	virtual void accept( Visitor & v ) override { v.visit( this ); }
+	virtual void accept( Visitor & v ) const override { v.visit( this ); }
+
+	virtual Declaration * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
+	virtual void print( std::ostream & os, Indenter indent = {} ) const override final {
+		os << "AdtDecl ... " << indent;
+	}
+	
+private:
+	virtual const char * typeString() const override {
+		return "AdtDecl";
+	}
+};
+
 class TraitDecl : public AggregateDecl {
 	typedef AggregateDecl Parent;
Index: src/SynTree/Mutator.h
===================================================================
--- src/SynTree/Mutator.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/SynTree/Mutator.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -30,4 +30,5 @@
 	virtual Declaration * mutate( UnionDecl * aggregateDecl ) = 0;
 	virtual Declaration * mutate( EnumDecl * aggregateDecl ) = 0;
+	virtual Declaration * mutate( AdtDecl * aggregateDecl ) = 0;
 	virtual Declaration * mutate( TraitDecl * aggregateDecl ) = 0;
 	virtual Declaration * mutate( TypeDecl * typeDecl ) = 0;
Index: src/SynTree/SynTree.h
===================================================================
--- src/SynTree/SynTree.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/SynTree/SynTree.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -31,4 +31,5 @@
 class UnionDecl;
 class EnumDecl;
+class AdtDecl;
 class TraitDecl;
 class NamedTypeDecl;
Index: src/SynTree/Visitor.h
===================================================================
--- src/SynTree/Visitor.h	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/SynTree/Visitor.h	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -37,4 +37,6 @@
 	virtual void visit( EnumDecl * node ) { visit( const_cast<const EnumDecl *>(node) ); }
 	virtual void visit( const EnumDecl * aggregateDecl ) = 0;
+	virtual void visit( AdtDecl * node ) { visit( const_cast<const AdtDecl *>(node) ); }
+	virtual void visit( const AdtDecl * node ) = 0;
 	virtual void visit( TraitDecl * node ) { visit( const_cast<const TraitDecl *>(node) ); }
 	virtual void visit( const TraitDecl * aggregateDecl ) = 0;
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Validate/Autogen.cpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -522,5 +522,5 @@
 
 void StructFuncGenerator::genADTFuncs() {
-	if ( decl->kind != ast::AggregateDecl::ADT ) return;
+	if ( decl->kind != ast::AggregateDecl::Adt ) return;
 	assert( decl->members.size() == 2 );
 	auto first = (decl->members[0]).as<ast::ObjectDecl>();
Index: src/Validate/NoIdSymbolTable.hpp
===================================================================
--- src/Validate/NoIdSymbolTable.hpp	(revision 28f8f154b94c0b9fd3ef74a8d0de01187a5522c6)
+++ src/Validate/NoIdSymbolTable.hpp	(revision 561354fd73c46eb32cf2feb6781d0a72427490ac)
@@ -44,4 +44,5 @@
 	FORWARD_1( addStruct, const ast::StructDecl *    )
 	FORWARD_1( addEnum  , const ast::EnumDecl *      )
+	FORWARD_1( addAdt,    const ast::AdtDecl *		 )
 	FORWARD_1( addUnion , const ast::UnionDecl *     )
 	FORWARD_1( addTrait , const ast::TraitDecl *     )
