diff --git a/spec/compiler/codegen/const_spec.cr b/spec/compiler/codegen/const_spec.cr
index 0c8342261bd0c62dd593213991de357302d3e96f..7aab57a8315af99004c263fc2e0c0b34bb1e8ec4 100644
--- a/spec/compiler/codegen/const_spec.cr
+++ b/spec/compiler/codegen/const_spec.cr
@@ -87,7 +87,11 @@ describe "Codegen: const" do
   end
 
   it "declare constants in right order" do
-    run("A = 1 + 1; B = true ? A : 0; B").to_i.should eq(2)
+    run(%(
+      A = 1 + 1
+      B = true ? A : 0
+      B
+      )).to_i.should eq(2)
   end
 
   it "uses correct types lookup" do
@@ -255,4 +259,39 @@ describe "Codegen: const" do
       Foo::Y.value
       )).to_i.should eq(1)
   end
+
+  it "codegens constant that refers to another one later in the file through a method call" do
+    build(%(
+      def foo
+        1
+      end
+
+      class Some
+        CONST_1 = Some.method
+        CONST_2 = foo
+
+        def self.method
+          CONST_2
+        end
+      end
+
+      Some::CONST_1
+      ))
+  end
+
+  it "codegens constant that refers to another one later, twice" do
+    build(%(
+      def foo
+        1
+      end
+
+      class Some
+        CONST_1 = CONST_2
+        CONST_2 = CONST_3
+        CONST_3 = foo
+      end
+
+      Some::CONST_1
+      ))
+  end
 end
diff --git a/spec/compiler/type_inference/const_spec.cr b/spec/compiler/type_inference/const_spec.cr
index ad04e2c11523945058bd7d431dc0a3849251aba1..46484dcd92d6be434dc4f8a42517ded519b166af 100755
--- a/spec/compiler/type_inference/const_spec.cr
+++ b/spec/compiler/type_inference/const_spec.cr
@@ -162,4 +162,14 @@ describe "Type inference: const" do
       B::CONSTANT
       )) { bool }
   end
+
+  it "detects recursive constant definition" do
+    assert_error %(
+      A = B
+      B = A
+
+      A
+      ),
+      "recursive constant definition: A -> B -> A"
+  end
 end
diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr
index c1b7a973bbc312fb21bc1160ba6da848d33e45d0..dca831fcf4b9e328859f1cdad507b8ab29328384 100644
--- a/spec/spec_helper.cr
+++ b/spec/spec_helper.cr
@@ -130,7 +130,7 @@ end
 def build(code)
   node = parse code
   result = infer_type node
-  result.program.build result.node, single_module: true
+  result.program.build result.node, single_module: false
 end
 
 class Crystal::SpecRunOutput
diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr
index 1c17c9f545630b089fd3022ff4e5d38c113a676f..301e5a0834e175802585ba9018c01f1b6c6aea7a 100644
--- a/src/compiler/crystal/codegen/codegen.cr
+++ b/src/compiler/crystal/codegen/codegen.cr
@@ -640,7 +640,7 @@ module Crystal
       # Initialize constants if they are used
       if target.is_a?(Path)
         const = target.target_const.not_nil!
-        declare_const(const)
+        declare_const const
         @last = llvm_nil
         return false
       end
@@ -874,10 +874,10 @@ module Crystal
       if const = node.target_const
         global_name = const.llvm_name
 
-        # TODO: the `||` part is to take care of constants that, for their
-        # initialization, depend on a constant that comes later in the code.
-        # We should maybe give an error in the type inference phase in this case.
-        global = @main_mod.globals[global_name]? || declare_const(const).not_nil!
+        global = @main_mod.globals[global_name]?
+        unless global
+          node.raise "Bug: global not found for #{const}"
+        end
 
         if @llvm_mod != @main_mod
           global = @llvm_mod.globals[global_name]?
@@ -902,7 +902,17 @@ module Crystal
     end
 
     def declare_const(const, global_name = const.llvm_name)
-      return nil unless const.used
+      return unless const.used
+
+      # First declare constants this constant depends on
+      const.dependencies.try &.each do |dep|
+        declare_const dep
+      end
+
+      # The constant might be already codegened
+      if global = @main_mod.globals[global_name]?
+        return global
+      end
 
       global = @main_mod.globals.add(llvm_type(const.value.type), global_name)
 
diff --git a/src/compiler/crystal/program.cr b/src/compiler/crystal/program.cr
index 0d951f441d58127f2377ccc145a9f63be4335011..95a89f968ca8a98f2b292ebb77ef7132ac0406a3 100644
--- a/src/compiler/crystal/program.cr
+++ b/src/compiler/crystal/program.cr
@@ -15,6 +15,7 @@ module Crystal
     getter splat_expansions
     property vars
     property literal_expander
+    getter consts_stack
 
     def initialize
       super(self, self, "main")
@@ -109,6 +110,7 @@ module Crystal
       @macro_expander = MacroExpander.new self
       @def_macros = [] of Def
       @splat_expansions = {} of Def => Type
+      @consts_stack = [] of Const
 
       define_primitives
     end
@@ -147,6 +149,18 @@ module Crystal
       flags.add(flag)
     end
 
+    def push_const(const)
+      if last_const = @consts_stack.last?
+        last_const.add_dependency const
+      end
+
+      @consts_stack.push const
+    end
+
+    def pop_const
+      @consts_stack.pop
+    end
+
     def program
       self
     end
diff --git a/src/compiler/crystal/semantic/type_inference.cr b/src/compiler/crystal/semantic/type_inference.cr
index b227430f87c3e24ea11c63ed85015bf86e3ffed0..105dd27fd8c332dab081894604ea1a2e8278c28e 100644
--- a/src/compiler/crystal/semantic/type_inference.cr
+++ b/src/compiler/crystal/semantic/type_inference.cr
@@ -1772,12 +1772,22 @@ module Crystal
       case type
       when Const
         unless type.value.type?
+          if type.visited?
+            node.raise "recursive constant definition: #{@mod.consts_stack.join " -> "} -> #{type}"
+          end
+
+          type.visited = true
+
           meta_vars = MetaVars.new
           const_def = Def.new("const", [] of Arg)
           type_visitor = TypeVisitor.new(@mod, meta_vars, const_def)
           type_visitor.types = type.scope_types
           type_visitor.scope = type.scope
+
+          @mod.push_const type
           type.value.accept type_visitor
+          @mod.pop_const
+
           type.vars = const_def.vars
         end
         node.target_const = type
diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr
index 8690cb86d7453346b5c698cad335590ab0c085df..8d2770f8712ec001810afc30e54917485e40ace2 100644
--- a/src/compiler/crystal/types.cr
+++ b/src/compiler/crystal/types.cr
@@ -2551,10 +2551,18 @@ module Crystal
     getter scope
     property! vars
     property used
+    property dependencies
+    property? visited
 
     def initialize(program, container, name, @value, @scope_types = [] of Type, @scope = nil)
       super(program, container, name)
       @used = false
+      @visited = false
+    end
+
+    def add_dependency(const)
+      dependencies = @dependencies ||= [] of Const
+      dependencies.push const
     end
 
     def type_desc