There's no need to join back to the table to do the DELETE. You can delete from the table by deleting from the CTE.
Here's the OPs original data in a readily consumable format...
--===== Create and populate a test table on-the-fly
SET DATEFORMAT DMY
;
SELECT [Timestamp] = CONVERT(DATE ,d.[Timestamp])
,Customer = CONVERT(CHAR(1) ,d.Customer)
,Data = CONVERT(VARCHAR(10),d.Data)
INTO #TestTable -- DROP TABLE #TestTable
FROM (
SELECT '3/03/2016','A','aaaaa' UNION ALL
SELECT '1/02/2016','A','bbbbbb' UNION ALL
SELECT '1/01/2016','A','cccccccc' UNION ALL
SELECT '1/12/2015','A','aaaaa' UNION ALL
SELECT '31/10/2015','B','bbbbbb' UNION ALL
SELECT '30/09/2015','B','cccccccc' UNION ALL
SELECT '30/08/2015','B','aaaaa' UNION ALL
SELECT '30/07/2015','B','bbbbbb' UNION ALL
SELECT '29/06/2015','B','cccccccc'
) d ([Timestamp],Customer,Data)
;
Here's the DELETE through the cte. Try it. It works just fine.
--===== Delete row in the table through the cte
WITH cteDelete AS
(
SELECT Customer
,RowNum = ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY [TimeStamp] DESC)
FROM #TestTable
)
DELETE FROM cteDelete
WHERE RowNum > 3
;
--Jeff Moden
Change is inevitable... Change for the better is not.