The following SQL separates tables according to their relationship. The problem is with the tables that sort under the 3000 series. Tables that are part of foreign keys and
You can use an iterative algorithm, which is probably less convoluted than a CTE. Here's an example that sorts according to depth:
declare @level int      -- Current depth
       ,@count int      
-- Step 1: Start with tables that have no FK dependencies
--  
if object_id ('tempdb..#Tables') is not null
    drop table #Tables
select s.name + '.' + t.name  as TableName
      ,t.object_id            as TableID
      ,0                      as Ordinal
  into #Tables
  from sys.tables t
  join sys.schemas s
    on t.schema_id = s.schema_id
 where not exists
       (select 1
          from sys.foreign_keys f
         where f.parent_object_id = t.object_id)
set @count = @@rowcount         
set @level = 0
-- Step 2: For a given depth this finds tables joined to 
-- tables at this given depth.  A table can live at multiple 
-- depths if it has more than one join path into it, so we 
-- filter these out in step 3 at the end.
--
while @count > 0 begin
    insert #Tables (
           TableName
          ,TableID
          ,Ordinal
    ) 
    select s.name + '.' + t.name  as TableName
          ,t.object_id            as TableID
          ,@level + 1             as Ordinal
      from sys.tables t
      join sys.schemas s
        on s.schema_id = t.schema_id
     where exists
           (select 1
              from sys.foreign_keys f
              join #Tables tt
                on f.referenced_object_id = tt.TableID
               and tt.Ordinal = @level
               and f.parent_object_id = t.object_id
               and f.parent_object_id != f.referenced_object_id)
                   -- The last line ignores self-joins.  You'll
                   -- need to deal with these separately
   set @count = @@rowcount
   set @level = @level + 1
end
-- Step 3: This filters out the maximum depth an object occurs at
-- and displays the deepest first.
--
select t.Ordinal
      ,t.TableID
      ,t.TableName
  from #Tables t
  join (select TableName     as TableName
              ,Max (Ordinal) as Ordinal
          from #Tables
         group by TableName) tt
    on t.TableName = tt.TableName
   and t.Ordinal = tt.Ordinal
 order by t.Ordinal desc