There is no way to replace object names with variables in a query without using dynamic sql, so you are heading down the right path. As an aside though you can remove your column cursor, and you can get a full column list using SQL Server's XML extensions to concatenate the columns:
DECLARE @Cols NVARCHAR(MAX) = STUFF((SELECT ',' + c.Name
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@tbl)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
This won't make much difference at all, but every little helps, and avoids allocating memory to a cursor. It does also make it easier to get the columns common to both tables as you can use an INNER JOIN, or INTERSECT to get the relevant columns.
The other change I would make (although this is much more subjective) is that I would use the system views for your schema
information, rather than the INFORMATION_SCHEMA
, the information schema, although ANSI standard and more guaranteed does
have its flaws, and the system views are more accurate and contain more information. Aaron Bertrand makes a much better case than me in this article.