diff --git a/encompass-cs/Attributes/QueryWith.cs b/encompass-cs/Attributes/QueryWith.cs
new file mode 100644
index 0000000..3ae11a6
--- /dev/null
+++ b/encompass-cs/Attributes/QueryWith.cs
@@ -0,0 +1,28 @@
+using Encompass.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Encompass
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class QueryWith : Attribute
+    {
+        public readonly HashSet<Type> queryWithTypes = new HashSet<Type>();
+
+        public QueryWith(params Type[] queryWithTypes)
+        {
+            foreach (var queryWithType in queryWithTypes)
+            {
+                var isComponent = queryWithType.GetInterfaces().Contains(typeof(IComponent));
+
+                if (!isComponent)
+                {
+                    throw new IllegalReadTypeException("{0} must be a Component", queryWithType.Name);
+                }
+
+                this.queryWithTypes.Add(queryWithType);
+            }
+        }
+    }
+}
diff --git a/encompass-cs/Attributes/QueryWithout.cs b/encompass-cs/Attributes/QueryWithout.cs
new file mode 100644
index 0000000..77f1e9f
--- /dev/null
+++ b/encompass-cs/Attributes/QueryWithout.cs
@@ -0,0 +1,28 @@
+using Encompass.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Encompass
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class QueryWithout : Attribute
+    {
+        public readonly HashSet<Type> queryWithoutTypes = new HashSet<Type>();
+
+        public QueryWithout(params Type[] queryWithoutTypes)
+        {
+            foreach (var type in queryWithoutTypes)
+            {
+                var isComponent = type.GetInterfaces().Contains(typeof(IComponent));
+
+                if (!isComponent)
+                {
+                    throw new IllegalReadTypeException("{0} must be a Component", type.Name);
+                }
+
+                this.queryWithoutTypes.Add(type);
+            }
+        }
+    }
+}
diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs
index 6e44131..5d3f09a 100644
--- a/encompass-cs/Collections/ComponentStore.cs
+++ b/encompass-cs/Collections/ComponentStore.cs
@@ -7,11 +7,11 @@ namespace Encompass
     internal class ComponentStore
     {
         private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512);
-        private ComponentBitSet componentBitSet;
+        public ComponentBitSet ComponentBitSet { get; private set; }
 
         public ComponentStore(Dictionary<Type, int> typeToIndex)
         {
-            componentBitSet = new ComponentBitSet(typeToIndex);
+            ComponentBitSet = new ComponentBitSet(typeToIndex);
         }
 
         public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
@@ -33,7 +33,7 @@ namespace Encompass
 
         public void FinishRegistering()
         {
-            componentBitSet.FinishRegistering();
+            ComponentBitSet.FinishRegistering();
         }
 
         private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
@@ -54,7 +54,7 @@ namespace Encompass
 
         public BitSet1024 EntityBitArray(Entity entity)
         {
-            return componentBitSet.EntityBitArray(entity);
+            return ComponentBitSet.EntityBitArray(entity);
         }
 
         public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent
@@ -65,18 +65,18 @@ namespace Encompass
         public void Set<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
         {
             Lookup<TComponent>().Set(entity, component);
-            componentBitSet.Set<TComponent>(entity);
+            ComponentBitSet.Set<TComponent>(entity);
         }
 
         public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
         {
-            componentBitSet.Set<TComponent>(entity);
+            ComponentBitSet.Set<TComponent>(entity);
             return Lookup<TComponent>().Set(entity, component, priority);
         }
 
         public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
         {
-            componentBitSet.RemoveComponent<TComponent>(entity);
+            ComponentBitSet.RemoveComponent<TComponent>(entity);
             Lookup<TComponent>().Remove(entity);
         }
 
@@ -86,7 +86,7 @@ namespace Encompass
             {
                 entry.Remove(entity);
             }
-            componentBitSet.RemoveEntity(entity);
+            ComponentBitSet.RemoveEntity(entity);
         }
 
         public bool Any<TComponent>() where TComponent : struct, IComponent
@@ -117,7 +117,7 @@ namespace Encompass
 
         public void ClearAll()
         {
-            componentBitSet.Clear();
+            ComponentBitSet.Clear();
             foreach (var store in Stores.Values)
             {
                 store.Clear();
@@ -127,7 +127,7 @@ namespace Encompass
         public void SwapWith(ComponentStore other)
         {
             (Stores, other.Stores) = (other.Stores, Stores);
-            (componentBitSet, other.componentBitSet) = (other.componentBitSet, componentBitSet);
+            (ComponentBitSet, other.ComponentBitSet) = (other.ComponentBitSet, ComponentBitSet);
         }
     }
 }
diff --git a/encompass-cs/ComponentUpdateManager.cs b/encompass-cs/ComponentUpdateManager.cs
index 8b371ee..d0ee527 100644
--- a/encompass-cs/ComponentUpdateManager.cs
+++ b/encompass-cs/ComponentUpdateManager.cs
@@ -197,14 +197,7 @@ namespace Encompass
             UpToDateComponentStore.Remove<TComponent>(entity);
         }
 
-        internal BitSet1024 PendingBits(Entity entity)
-        {
-            return pendingComponentStore.EntityBitArray(entity);
-        }
-
-        internal BitSet1024 ExistingBits(Entity entity)
-        {
-            return existingComponentStore.EntityBitArray(entity);
-        }
+        internal ComponentBitSet PendingBits { get { return pendingComponentStore.ComponentBitSet; } }
+        internal ComponentBitSet ExistingBits {  get { return existingComponentStore.ComponentBitSet; } }
     }
 }
diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs
index dfb3f35..8e0a8ae 100644
--- a/encompass-cs/Engine.cs
+++ b/encompass-cs/Engine.cs
@@ -3,6 +3,7 @@ using System.Reflection;
 using System.Collections.Generic;
 using System.Linq;
 using Encompass.Exceptions;
+using Encompass.Collections;
 
 namespace Encompass
 {
@@ -21,6 +22,8 @@ namespace Encompass
         internal readonly HashSet<Type> receiveTypes = new HashSet<Type>();
         internal readonly HashSet<Type> writeTypes = new HashSet<Type>();
         internal readonly HashSet<Type> writePendingTypes = new HashSet<Type>();
+        internal readonly HashSet<Type> queryWithTypes = new HashSet<Type>();
+        internal readonly HashSet<Type> queryWithoutTypes = new HashSet<Type>();
         internal readonly Dictionary<Type, int> writePriorities = new Dictionary<Type, int>();
         internal readonly int defaultWritePriority = 0;
 
@@ -36,6 +39,8 @@ namespace Encompass
         private ComponentUpdateManager componentUpdateManager;
         private TimeManager timeManager;
 
+        private EntitySetQuery entityQuery;
+
         protected Engine()
         {
             ID = Guid.NewGuid();
@@ -82,6 +87,18 @@ namespace Encompass
             {
                 readPendingTypes = readsPendingAttribute.readPendingTypes;
             }
+
+            var queryWithAttribute = GetType().GetCustomAttribute<QueryWith>(false);
+            if (queryWithAttribute != null)
+            {
+                queryWithTypes = queryWithAttribute.queryWithTypes;
+            }
+
+            var queryWithoutAttribute = GetType().GetCustomAttribute<QueryWithout>(false);
+            if (queryWithoutAttribute != null)
+            {
+                queryWithoutTypes = queryWithoutAttribute.queryWithoutTypes;
+            }
         }
 
         public override bool Equals(object obj)
@@ -612,16 +629,49 @@ namespace Encompass
             timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
         }
 
+        protected IEnumerable<Entity> QueryEntities()
+        {
+            foreach (var entity in entityQuery.FilterEntities(entityManager.Entities, componentUpdateManager.PendingBits, componentUpdateManager.ExistingBits))
+            {
+                yield return entity;
+            }
+        }
+
         /// <summary>
         /// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria.
         /// </summary>
-        protected EntitySetQueryBuilder EntityQueryBuilder()
+        internal void BuildEntityQuery()
         {
-            return new EntitySetQueryBuilder(
-                entityManager,
-                componentUpdateManager,
-                readPendingTypes,
-                readTypes
+            var withMask = BitSet1024Builder.Zeroes();
+            foreach (var type in queryWithTypes)
+            {
+                withMask = withMask.Set(componentUpdateManager.TypeToIndex[type]);
+            }
+
+            var withoutMask = BitSet1024Builder.Zeroes();
+            foreach (var type in queryWithoutTypes)
+            {
+                withoutMask = withoutMask.Set(componentUpdateManager.TypeToIndex[type]);
+            }
+
+            var pendingMask = BitSet1024Builder.Zeroes();
+            foreach (var type in readPendingTypes)
+            {
+                pendingMask = pendingMask.Set(componentUpdateManager.TypeToIndex[type]);
+            }
+
+            var existingMask = BitSet1024Builder.Zeroes();
+            foreach (var type in readTypes)
+            {
+                existingMask = existingMask.Set(componentUpdateManager.TypeToIndex[type]);
+            }
+
+            entityQuery = new EntitySetQuery(
+                withMask.And(pendingMask),
+                withMask.And(existingMask),
+                withoutMask.And(pendingMask),
+                withoutMask.And(existingMask),
+                withMask.Not()
             );
         }
     }
diff --git a/encompass-cs/EntitySetQuery.cs b/encompass-cs/EntitySetQuery.cs
index 60bd110..899ddcc 100644
--- a/encompass-cs/EntitySetQuery.cs
+++ b/encompass-cs/EntitySetQuery.cs
@@ -4,20 +4,16 @@ using Encompass.Collections;
 
 namespace Encompass
 {
-    public struct EntitySetQuery : IEnumerable<Entity>
+    internal struct EntitySetQuery
     {
-        private EntityManager EntityManager { get; }
-        private ComponentUpdateManager ComponentUpdateManager { get; }
         private BitSet1024 WithPendingMask { get; }
         private BitSet1024 WithExistingMask { get; }
         private BitSet1024 WithoutPendingMask { get; }
         private BitSet1024 WithoutExistingMask { get; }
         private BitSet1024 NotWithMask { get; }
 
-        internal EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, BitSet1024 withPendingMask, BitSet1024 withExistingMask, BitSet1024 withoutPendingMask, BitSet1024 withoutExistingMask, BitSet1024 notWithMask)
+        internal EntitySetQuery(BitSet1024 withPendingMask, BitSet1024 withExistingMask, BitSet1024 withoutPendingMask, BitSet1024 withoutExistingMask, BitSet1024 notWithMask)
         {
-            EntityManager = entityManager;
-            ComponentUpdateManager = componentUpdateManager;
             WithPendingMask = withPendingMask;
             WithExistingMask = withExistingMask;
             WithoutPendingMask = withoutPendingMask;
@@ -25,28 +21,23 @@ namespace Encompass
             NotWithMask = notWithMask;
         }
 
-        public IEnumerator<Entity> GetEnumerator()
+        public IEnumerable<Entity> FilterEntities(IEnumerable<Entity> entities, ComponentBitSet pendingBitLookup, ComponentBitSet existingBitLookup)
         {
-            foreach (var entity in EntityManager.Entities)
+            foreach (var entity in entities)
             {
-                var pendingBits = ComponentUpdateManager.PendingBits(entity);
-                var existingBits = ComponentUpdateManager.ExistingBits(entity);
+                var pendingBits = pendingBitLookup.EntityBitArray(entity);
+                var existingBits = existingBitLookup.EntityBitArray(entity);
 
                 var pending = WithPendingMask.And(pendingBits);
                 var existing = WithExistingMask.And(existingBits);
                 var withCheck = pending.Or(existing).Or(NotWithMask);
 
-                var pendingForbidden = WithoutPendingMask.And(pendingBits);
-                var existingForbidden = WithoutExistingMask.And(existingBits);
+                var pendingForbidden = WithoutPendingMask.And(pendingBits).Not();
+                var existingForbidden = WithoutExistingMask.And(existingBits).Not();
                 var withoutCheck = pendingForbidden.And(existingForbidden);
 
                 if (withCheck.And(withoutCheck).AllTrue()) { yield return entity; }
             }
         }
-
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return GetEnumerator();
-        }
     }
 }
diff --git a/encompass-cs/EntitySetQueryBuilder.cs b/encompass-cs/EntitySetQueryBuilder.cs
deleted file mode 100644
index 00452c5..0000000
--- a/encompass-cs/EntitySetQueryBuilder.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Encompass.Collections;
-
-namespace Encompass
-{
-    /// <summary>
-    /// EntitySetQuery is used to efficiently obtain a set of Entities that have all required Components and do not have any forbidden Components.
-    /// </summary>
-    public class EntitySetQueryBuilder
-    {
-        internal EntitySetQueryBuilder(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, IEnumerable<Type> pendingTypes, IEnumerable<Type> existingTypes)
-        {
-            EntityManager = entityManager;
-            ComponentUpdateManager = componentUpdateManager;
-            WithMask = BitSet1024Builder.Zeroes();
-            WithoutMask = BitSet1024Builder.Zeroes();
-            
-            PendingMask = BitSet1024Builder.Zeroes();
-            foreach (var type in pendingTypes)
-            {
-                PendingMask = PendingMask.Set(componentUpdateManager.TypeToIndex[type]);
-            }
-
-            ExistingMask = BitSet1024Builder.Zeroes();
-            foreach (var type in existingTypes)
-            {
-                ExistingMask = ExistingMask.Set(componentUpdateManager.TypeToIndex[type]);
-            }
-        }
-
-        private EntityManager EntityManager { get; }
-        private ComponentUpdateManager ComponentUpdateManager { get; }
-        private BitSet1024 WithMask { get; set; }
-        private BitSet1024 WithoutMask { get; set; }
-        private BitSet1024 PendingMask { get; set; }
-        private BitSet1024 ExistingMask { get; set; }
-
-        /// <summary>
-        /// Designates that the given component type is required.
-        /// </summary>
-        public EntitySetQueryBuilder With<TComponent>() where TComponent : struct, IComponent
-        {
-            WithMask = WithMask.Set(ComponentUpdateManager.TypeToIndex[typeof(TComponent)]);
-            return this;
-        }
-
-        /// <summary>
-        /// Designates that the given component type is forbidden.
-        /// </summary>
-        public EntitySetQueryBuilder Without<TComponent>() where TComponent : struct, IComponent
-        {
-            WithoutMask = WithoutMask.Set(ComponentUpdateManager.TypeToIndex[typeof(TComponent)]);
-            return this;
-        }
-
-        public EntitySetQuery Build()
-        {
-            return new EntitySetQuery(
-                EntityManager,
-                ComponentUpdateManager,
-                WithMask.And(PendingMask),
-                WithMask.And(ExistingMask),
-                WithoutMask.And(PendingMask),
-                WithoutMask.And(ExistingMask),
-                WithMask.Not()
-            );
-        }
-    }
-}
diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs
index 1e88a88..3c82f8c 100644
--- a/encompass-cs/WorldBuilder.cs
+++ b/encompass-cs/WorldBuilder.cs
@@ -173,9 +173,6 @@ namespace Encompass
                 typeToReaders[receiveType].Add(engine);
             }
 
-            // System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(typeof(TEngine).GetRuntimeMethod("Update", new Type[] { typeof(double) }).MethodHandle);
-            // typeof(TEngine).GetMethod("Update", new Type[] { typeof(double) }).MethodHandle.GetFunctionPointer();
-
             return engine;
         }
 
@@ -385,6 +382,7 @@ namespace Encompass
             foreach (var engine in engineGraph.TopologicalSort())
             {
                 engineOrder.Add(engine);
+                engine.BuildEntityQuery();
             }
 
             var world = new World(
diff --git a/test/EngineTest.cs b/test/EngineTest.cs
index b36541d..1b36ce6 100644
--- a/test/EngineTest.cs
+++ b/test/EngineTest.cs
@@ -1095,6 +1095,7 @@ namespace Tests
             struct MockComponentD : IComponent { }
 
             [Reads(typeof(MockComponent), typeof(MockComponentB))]
+            [QueryWith(typeof(MockComponent), typeof(MockComponentB))]
             class EntityQueryWithComponentsEngine : Engine
             {
                 private List<Entity> entities;
@@ -1107,8 +1108,10 @@ namespace Tests
                 public override void Update(double dt)
                 {
                     entities.Clear();
-
-                    entities.AddRange(QueryEntities().With<MockComponent>().With<MockComponentB>());
+                    foreach (var entity in QueryEntities())
+                    {
+                        entities.Add(entity);
+                    }
                 }
             }
 
@@ -1140,6 +1143,7 @@ namespace Tests
             }
 
             [Reads(typeof(MockComponent))]
+            [QueryWithout(typeof(MockComponent))]
             class EntityQueryWithoutComponentsEngine : Engine
             {
                 private List<Entity> entities;
@@ -1152,8 +1156,7 @@ namespace Tests
                 public override void Update(double dt)
                 {
                     entities.Clear();
-
-                    entities.AddRange(QueryEntities().Without<MockComponent>());
+                    entities.AddRange(QueryEntities());
                 }
             }
 
@@ -1185,6 +1188,8 @@ namespace Tests
             }
 
             [Reads(typeof(MockComponent), typeof(MockComponentB), typeof(MockComponentD))]
+            [QueryWith(typeof(MockComponent), typeof(MockComponentB))]
+            [QueryWithout(typeof(MockComponentD))]
             class EntityQueryWithandWithoutComponentsEngine : Engine
             {
                 private List<Entity> entities;
@@ -1198,9 +1203,7 @@ namespace Tests
                 {
                     entities.Clear();
 
-                    entities.AddRange(QueryEntities().With<MockComponent>()
-                                                     .With<MockComponentB>()
-                                                     .Without<MockComponentD>());
+                    entities.AddRange(QueryEntities());
                 }
             }
 
@@ -1246,7 +1249,7 @@ namespace Tests
             {
                 public override void Update(double dt)
                 {
-                    foreach (var entity in QueryEntities().With<MockComponent>())
+                    foreach (var entity in ReadEntities<MockComponent>())
                     {
                         SetComponent(entity, new MockComponentB());
                     }
@@ -1254,6 +1257,7 @@ namespace Tests
             }
 
             [ReadsPending(typeof(MockComponentB))]
+            [QueryWith(typeof(MockComponentB))]
             class EntityQueryWithPendingComponentsEngine : Engine
             {
                 private List<Entity> entities;
@@ -1266,8 +1270,7 @@ namespace Tests
                 public override void Update(double dt)
                 {
                     entities.Clear();
-
-                    entities.AddRange(QueryEntities().With<MockComponentB>());
+                    entities.AddRange(QueryEntities());
                 }
             }
 
@@ -1293,6 +1296,7 @@ namespace Tests
             }
 
             [ReadsPending(typeof(MockComponentB))]
+            [QueryWithout(typeof(MockComponentB))]
             class EntityQueryWithoutPendingComponentsEngine : Engine
             {
                 private List<Entity> entities;
@@ -1305,8 +1309,7 @@ namespace Tests
                 public override void Update(double dt)
                 {
                     entities.Clear();
-
-                    entities.AddRange(QueryEntities().Without<MockComponentB>());
+                    entities.AddRange(QueryEntities());
                 }
             }
 
@@ -1339,12 +1342,12 @@ namespace Tests
             {
                 public override void Update(double dt)
                 {
-                    foreach (var entity in QueryEntities().With<MockComponentC>())
+                    foreach (var entity in ReadEntities<MockComponentC>())
                     {
                         SetComponent(entity, new MockComponent());
                     }
 
-                    foreach (var entity in QueryEntities().With<MockComponentD>())
+                    foreach (var entity in ReadEntities<MockComponentD>())
                     {
                         SetComponent(entity, new MockComponent());
                         SetComponent(entity, new MockComponentB());
@@ -1353,6 +1356,8 @@ namespace Tests
             }
 
             [ReadsPending(typeof(MockComponent), typeof(MockComponentB))]
+            [QueryWith(typeof(MockComponent))]
+            [QueryWithout(typeof(MockComponentB))]
             class EntityQueryWithAndWithoutPendingComponentsEngine : Engine
             {
                 private List<Entity> entities;
@@ -1366,7 +1371,7 @@ namespace Tests
                 {
                     entities.Clear();
 
-                    entities.AddRange(QueryEntities().With<MockComponent>().Without<MockComponentB>());
+                    entities.AddRange(QueryEntities());
                 }
             }
 
@@ -1400,7 +1405,7 @@ namespace Tests
             {
                 public override void Update(double dt)
                 {
-                    foreach (var entity in QueryEntities().With<MockComponentC>())
+                    foreach (var entity in ReadEntities<MockComponentC>())
                     {
                         SetComponent(entity, new MockComponentB());
                     }
@@ -1409,6 +1414,7 @@ namespace Tests
 
             [ReadsPending(typeof(MockComponentB))]
             [Reads(typeof(MockComponent))]
+            [QueryWith(typeof(MockComponent), typeof(MockComponentB))]
             class EntityQueryWithPendingAndNonPendingComponents : Engine
             {
                 private List<Entity> entities;
@@ -1421,8 +1427,7 @@ namespace Tests
                 public override void Update(double dt)
                 {
                     entities.Clear();
-
-                    entities.AddRange(QueryEntities().With<MockComponent>().With<MockComponentB>());
+                    entities.AddRange(QueryEntities());
                 }
             }