diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3363/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3363/FixtureByCode.cs
new file mode 100644
index 00000000000..04e614a5d0e
--- /dev/null
+++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3363/FixtureByCode.cs
@@ -0,0 +1,131 @@
+//------------------------------------------------------------------------------
+// 
+//     This code was generated by AsyncGenerator.
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// 
+//------------------------------------------------------------------------------
+
+
+using System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.DomainModel;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+using NHibernate.Linq;
+
+namespace NHibernate.Test.NHSpecificTest.GH3363
+{
+	using System.Threading.Tasks;
+	/// 
+	/// Fixture using 'by code' mappings
+	/// 
+	/// 
+	/// This fixture is identical to  except the  mapping is performed 
+	/// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach
+	/// if you prefer.
+	/// 
+	[TestFixture]
+	public class ByCodeFixtureAsync : TestCaseMappingByCode
+	{
+		protected override HbmMapping GetMappings()
+		{
+			var mapper = new ModelMapper();
+		
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Identity));
+				rc.Property(x => x.Name);
+				rc.Discriminator(x => x.Column("kind"));
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing,  m =>{
+						m.NotFound(NotFoundMode.Ignore);
+						m.Column("thingId");
+					});
+				rc.DiscriminatorValue(1);
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing, m => {
+					m.NotFound(NotFoundMode.Ignore);
+					m.Column("thingId");
+				});
+				rc.DiscriminatorValue(2);
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+				
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+
+			});
+			return mapper.CompileMappingForAllExplicitlyAddedEntities();
+		}
+
+		protected override void OnSetUp()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var t1 = new Thing1() { Name = "don't care",Id="00001" };
+				session.Save(t1);
+				var t2 = new Thing2() { Name = "look for this",Id="00002" };
+				session.Save(t2);
+				var child1 = new Child1 { Name = "Child1",Thing=t1 };
+				session.Save(child1);
+				var child2 = new Child2 { Name = "Child1", Thing = t2 };
+				session.Save(child2);
+				transaction.Commit();
+			}
+		}
+
+		protected override void OnTearDown()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				// The HQL delete does all the job inside the database without loading the entities, but it does
+				// not handle delete order for avoiding violating constraints if any. Use
+				// session.Delete("from System.Object");
+				// instead if in need of having NHbernate ordering the deletes, but this will cause
+				// loading the entities in the session.
+				session.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+				transaction.Commit();
+			}
+		}
+
+		[Test]
+		public async Task LookForThingOfTypeThing1Async()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				/*
+				 * wrong statement created
+				 * select mother0_.Id as id1_0_, mother0_.Name as name3_0_,
+					mother0_.thingId as thingid4_0_, mother0_.kind as kind2_0_ from Mother mother0_ 
+					left outer join Thing2 thing2x1_ on 
+					mother0_.thingId=thing2x1_.Id where mother0_.kind='1' and thing2x1_.Id=?"
+				 * 
+				 */
+
+				var result = await (session.Query().Where(k => k is Child1 && (k as Child1).Thing.Id == "00001").ToListAsync());
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				await (transaction.CommitAsync());
+			}
+		}
+	}
+
+}
diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3363/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3363/FixtureByCode.cs
new file mode 100644
index 00000000000..db885fe56e4
--- /dev/null
+++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3363/FixtureByCode.cs
@@ -0,0 +1,158 @@
+//------------------------------------------------------------------------------
+// 
+//     This code was generated by AsyncGenerator.
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// 
+//------------------------------------------------------------------------------
+
+
+using System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.DomainModel;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+using NHibernate.Linq;
+
+namespace NHibernate.Test.NHSpecificTest.NH3363
+{
+	using System.Threading.Tasks;
+	/// 
+	/// Fixture using 'by code' mappings
+	/// 
+	/// 
+	/// This fixture is identical to  except the  mapping is performed 
+	/// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach
+	/// if you prefer.
+	/// 
+	[TestFixture]
+	public class ByCodeFixtureAsync : TestCaseMappingByCode
+	{
+		protected override HbmMapping GetMappings()
+		{
+			var mapper = new ModelMapper();
+		
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Identity));
+				rc.Property(x => x.Name);
+				rc.Discriminator(x => x.Column("kind"));
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing,  m =>{
+						m.NotFound(NotFoundMode.Ignore);
+						m.Column("thingId");
+					});
+				rc.DiscriminatorValue(1);
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing, m => {
+					m.NotFound(NotFoundMode.Ignore);
+					m.Column("thingId");
+				});
+				rc.DiscriminatorValue(2);
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+				
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+
+			});
+			return mapper.CompileMappingForAllExplicitlyAddedEntities();
+		}
+
+		protected override void OnSetUp()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var t1 = new Thing1() { Name = "don't care",Id="00001" };
+				session.Save(t1);
+				var t2 = new Thing2() { Name = "look for this",Id="00002" };
+				session.Save(t2);
+				var child1 = new Child1 { Name = "Child1",Thing=t1 };
+				session.Save(child1);
+				var child2 = new Child2 { Name = "Child1", Thing = t2 };
+				session.Save(child2);
+				transaction.Commit();
+			}
+		}
+
+		protected override void OnTearDown()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				// The HQL delete does all the job inside the database without loading the entities, but it does
+				// not handle delete order for avoiding violating constraints if any. Use
+				// session.Delete("from System.Object");
+				// instead if in need of having NHbernate ordering the deletes, but this will cause
+				// loading the entities in the session.
+				session.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+				transaction.Commit();
+			}
+		}
+
+		[Test]
+		public async Task LookForThingOfTypeThing2Async()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var result = await (session.Query().Where(k=>k is Child2 && (k as Child2).Thing.Id == "00002").ToListAsync());
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				await (transaction.CommitAsync());
+			}
+		}
+		[Test]
+		public async Task LookForThingOfTypeThing1Async()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var oftype = await (session.Query().Where(k => k is Child1).ToListAsync());
+				Assert.That(oftype, Has.Count.EqualTo(1));
+				Assert.That((oftype[0] as Child1).Thing, Is.Not.Null);
+				/*
+				 * wrong statement created
+				 * select mother0_.Id as id1_0_, mother0_.Name as name3_0_,
+					mother0_.thingId as thingid4_0_, mother0_.kind as kind2_0_ from Mother mother0_ 
+					left outer join Thing2 thing2x1_ on 
+					mother0_.thingId=thing2x1_.Id where mother0_.kind='1' and thing2x1_.Id=?"
+				 * 
+				 */
+
+				var result = await (session.Query().Where(k => k is Child1 && (k as Child1).Thing.Id == "00001").ToListAsync());
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				await (transaction.CommitAsync());
+			}
+		}
+		[Test]
+		public async Task LookForManyToOneByDescrAsync()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var result = await (session.Query().Where(k => k is Child2 && (k as Child2).Thing.Name == "look for this").ToListAsync());
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				await (transaction.CommitAsync());
+			}
+		}
+	}
+
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3363/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3363/Entities.cs
new file mode 100644
index 00000000000..a0bc11ed0bf
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3363/Entities.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace NHibernate.Test.NHSpecificTest.GH3363
+{
+	class Mother
+	{
+		public virtual int Id { get; set; }
+		public virtual string Name { get; set; }
+	}
+	
+	class Child1 : Mother
+	{
+		public virtual Thing1 Thing {  get; set; }
+	}
+	class Child2 : Mother
+	{
+		public virtual Thing2 Thing { get; set; }
+	}
+	class Thing1
+	{
+		public virtual string Id { get; set;}
+		public virtual string Name { get; set; }
+	}
+	class Thing2
+	{
+		public virtual string Id { get; set;}
+		public virtual string Name { get; set; }
+	}
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/GH3363/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3363/FixtureByCode.cs
new file mode 100644
index 00000000000..527de30c8fb
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/GH3363/FixtureByCode.cs
@@ -0,0 +1,119 @@
+using System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.DomainModel;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.GH3363
+{
+	/// 
+	/// Fixture using 'by code' mappings
+	/// 
+	/// 
+	/// This fixture is identical to  except the  mapping is performed 
+	/// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach
+	/// if you prefer.
+	/// 
+	[TestFixture]
+	public class ByCodeFixture : TestCaseMappingByCode
+	{
+		protected override HbmMapping GetMappings()
+		{
+			var mapper = new ModelMapper();
+		
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Identity));
+				rc.Property(x => x.Name);
+				rc.Discriminator(x => x.Column("kind"));
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing,  m =>{
+						m.NotFound(NotFoundMode.Ignore);
+						m.Column("thingId");
+					});
+				rc.DiscriminatorValue(1);
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing, m => {
+					m.NotFound(NotFoundMode.Ignore);
+					m.Column("thingId");
+				});
+				rc.DiscriminatorValue(2);
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+				
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+
+			});
+			return mapper.CompileMappingForAllExplicitlyAddedEntities();
+		}
+
+		protected override void OnSetUp()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var t1 = new Thing1() { Name = "don't care",Id="00001" };
+				session.Save(t1);
+				var t2 = new Thing2() { Name = "look for this",Id="00002" };
+				session.Save(t2);
+				var child1 = new Child1 { Name = "Child1",Thing=t1 };
+				session.Save(child1);
+				var child2 = new Child2 { Name = "Child1", Thing = t2 };
+				session.Save(child2);
+				transaction.Commit();
+			}
+		}
+
+		protected override void OnTearDown()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				// The HQL delete does all the job inside the database without loading the entities, but it does
+				// not handle delete order for avoiding violating constraints if any. Use
+				// session.Delete("from System.Object");
+				// instead if in need of having NHbernate ordering the deletes, but this will cause
+				// loading the entities in the session.
+				session.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+				transaction.Commit();
+			}
+		}
+
+		[Test]
+		public void LookForThingOfTypeThing1()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				/*
+				 * wrong statement created
+				 * select mother0_.Id as id1_0_, mother0_.Name as name3_0_,
+					mother0_.thingId as thingid4_0_, mother0_.kind as kind2_0_ from Mother mother0_ 
+					left outer join Thing2 thing2x1_ on 
+					mother0_.thingId=thing2x1_.Id where mother0_.kind='1' and thing2x1_.Id=?"
+				 * 
+				 */
+
+				var result = session.Query().Where(k => k is Child1 && (k as Child1).Thing.Id == "00001").ToList();
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				transaction.Commit();
+			}
+		}
+	}
+
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3363/Entities.cs b/src/NHibernate.Test/NHSpecificTest/NH3363/Entities.cs
new file mode 100644
index 00000000000..7a89c27a152
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3363/Entities.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace NHibernate.Test.NHSpecificTest.NH3363
+{
+	class Mother
+	{
+		public virtual int Id { get; set; }
+		public virtual string Name { get; set; }
+	}
+	
+	class Child1 : Mother
+	{
+		public virtual Thing1 Thing {  get; set; }
+	}
+	class Child2 : Mother
+	{
+		public virtual Thing2 Thing { get; set; }
+	}
+	class Thing1
+	{
+		public virtual string Id { get; set;}
+		public virtual string Name { get; set; }
+	}
+	class Thing2
+	{
+		public virtual string Id { get; set;}
+		public virtual string Name { get; set; }
+	}
+}
diff --git a/src/NHibernate.Test/NHSpecificTest/NH3363/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/NH3363/FixtureByCode.cs
new file mode 100644
index 00000000000..f839aeaebbf
--- /dev/null
+++ b/src/NHibernate.Test/NHSpecificTest/NH3363/FixtureByCode.cs
@@ -0,0 +1,146 @@
+using System.Linq;
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.DomainModel;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH3363
+{
+	/// 
+	/// Fixture using 'by code' mappings
+	/// 
+	/// 
+	/// This fixture is identical to  except the  mapping is performed 
+	/// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach
+	/// if you prefer.
+	/// 
+	[TestFixture]
+	public class ByCodeFixture : TestCaseMappingByCode
+	{
+		protected override HbmMapping GetMappings()
+		{
+			var mapper = new ModelMapper();
+		
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Identity));
+				rc.Property(x => x.Name);
+				rc.Discriminator(x => x.Column("kind"));
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing,  m =>{
+						m.NotFound(NotFoundMode.Ignore);
+						m.Column("thingId");
+					});
+				rc.DiscriminatorValue(1);
+			});
+			mapper.Subclass(rc =>
+			{
+				rc.Property(x => x.Name);
+				rc.ManyToOne(x => x.Thing, m => {
+					m.NotFound(NotFoundMode.Ignore);
+					m.Column("thingId");
+				});
+				rc.DiscriminatorValue(2);
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+				
+			});
+			mapper.Class(rc =>
+			{
+				rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
+				rc.Property(x => x.Name);
+
+			});
+			return mapper.CompileMappingForAllExplicitlyAddedEntities();
+		}
+
+		protected override void OnSetUp()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var t1 = new Thing1() { Name = "don't care",Id="00001" };
+				session.Save(t1);
+				var t2 = new Thing2() { Name = "look for this",Id="00002" };
+				session.Save(t2);
+				var child1 = new Child1 { Name = "Child1",Thing=t1 };
+				session.Save(child1);
+				var child2 = new Child2 { Name = "Child1", Thing = t2 };
+				session.Save(child2);
+				transaction.Commit();
+			}
+		}
+
+		protected override void OnTearDown()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				// The HQL delete does all the job inside the database without loading the entities, but it does
+				// not handle delete order for avoiding violating constraints if any. Use
+				// session.Delete("from System.Object");
+				// instead if in need of having NHbernate ordering the deletes, but this will cause
+				// loading the entities in the session.
+				session.CreateQuery("delete from System.Object").ExecuteUpdate();
+
+				transaction.Commit();
+			}
+		}
+
+		[Test]
+		public void LookForThingOfTypeThing2()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var result = session.Query().Where(k=>k is Child2 && (k as Child2).Thing.Id == "00002").ToList();
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				transaction.Commit();
+			}
+		}
+		[Test]
+		public void LookForThingOfTypeThing1()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var oftype = session.Query().Where(k => k is Child1).ToList();
+				Assert.That(oftype, Has.Count.EqualTo(1));
+				Assert.That((oftype[0] as Child1).Thing, Is.Not.Null);
+				/*
+				 * wrong statement created
+				 * select mother0_.Id as id1_0_, mother0_.Name as name3_0_,
+					mother0_.thingId as thingid4_0_, mother0_.kind as kind2_0_ from Mother mother0_ 
+					left outer join Thing2 thing2x1_ on 
+					mother0_.thingId=thing2x1_.Id where mother0_.kind='1' and thing2x1_.Id=?"
+				 * 
+				 */
+
+				var result = session.Query().Where(k => k is Child1 && (k as Child1).Thing.Id == "00001").ToList();
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				transaction.Commit();
+			}
+		}
+		[Test]
+		public void LookForManyToOneByDescr()
+		{
+			using (var session = OpenSession())
+			using (var transaction = session.BeginTransaction())
+			{
+				var result = session.Query().Where(k => k is Child2 && (k as Child2).Thing.Name == "look for this").ToList();
+
+				Assert.That(result, Has.Count.EqualTo(1));
+				transaction.Commit();
+			}
+		}
+	}
+
+}